当前位置:网站首页>【Template】Tree Chain Segmentation P3384
【Template】Tree Chain Segmentation P3384
2022-08-09 07:06:00 【swust_fang】
题目链接
//部分转自:https://www.luogu.org/problemnew/solution/P3384
Beginner tree chain division,I feel that this template question is easy to understand,But it's really huge.
知识点:
- 重儿子:对于每一个非叶子节点,among its sons The one with the largest number of sons is the heavy son of this node
- 轻儿子:对于每一个非叶子节点,among its sons non-heavy son All remaining sons are called light sons
- 叶子节点没有重儿子也没有轻儿子(Because it has no son..)
- 重边:An edge connecting any two heavy children is called a heavy edge
- 轻边:The rest is the light edge
- 重链:相邻重边连起来的 连接一条重儿子 的链叫重链
- 对于叶子节点,If it is a light son,Then there is a length with itself as the starting point1的链
- Every heavy chain starts with a light son
- (太智能了,A picture pops up,
The first is through twodfsto process the information
dfs1()
这个dfsThere are a few things to deal with:
- 标记每个点的深度dep[]
- 标记每个点的父亲fa[]
- 标记每个非叶子节点的子树大小(contains itself)
- 标记每个非叶子节点的重儿子编号son[]
void dfs1(int u,int pre,int dep)
{
f[u]=pre;
d[u]=dep;
size[u]=1;
for(int i=head[u];~i;i=edge[i].p)
{
int v=edge[i].to;
if(v==pre) continue;
dfs1(v,u,dep+1);
size[u]+=size[v];
if(size[v]>size[son[u]])
son[u]=v;
}
}
dfs2()
这个dfs2There are a few things to preprocess as well
- 标记每个点的新编号
- Assign the initial value of each point to the new number
- Process the top of the chain where each point is
- Process each chain
void dfs2(int u,int tp)
{
top[u]=tp;
dfn[u]=++t;
tim[t]=u;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];~i;i=edge[i].p)
{
int v=edge[i].to;
if(v!=f[u]&&v!=son[u]) dfs2(v,v);
}
}
顺序:Deal with the heavy son first and then deal with the light
Probably the most important process is these two,Divided by light and heavy son(Deal with the heavy son first and then deal with the light)First, its tree structure can be converted into a linear structure,Used for line segment trees to handle various on-tree information,但是不同于dfstraverse directly in order,The new number after the tree chain is split,In most query processing intervals are continuous intervals,In fact, it is to split the tree into individual chains,Then elegant(baoli)of solving various problems.
代码:
//#pragma comment (linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>
#include<list>
#include<time.h>
#define myself i,l,r
#define lson i<<1
#define rson i<<1|1
#define Lson i<<1,l,mid
#define Rson i<<1|1,mid+1,r
#define half (l+r)/2
#define lowbit(x) x&(-x)
#define min4(a, b, c, d) min(min(a,b),min(c,d))
#define min3(x, y, z) min(min(x,y),z)
#define max3(x, y, z) max(max(x,y),z)
#define max4(a, b, c, d) max(max(a,b),max(c,d))
#define pii make_pair
#define pr pair<int,int>
//freopen("E://1.in","r",stdin);
//freopen("E://1.out","w",stdout);
typedef unsigned long long ull;
typedef long long ll;
const int inff = 0x3f3f3f3f;
const long long inFF = 9223372036854775807;
const int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
const int mdir[8][2] = {0, 1, 0, -1, 1, 0, -1, 0, 1, 1, -1, 1, 1, -1, -1, -1};
const double eps = 1e-10;
const double PI = acos(-1.0);
const double E = 2.718281828459;
using namespace std;
//const int mod=1e9+7;
const int maxn=2e5+5;
int d[maxn];//深度
int son[maxn];//The heavy son of a certain point
int top[maxn];//The point is at the head of the chain
int dfn[maxn];//Timestamp of a point
int tim[maxn];//Record the node subscript corresponding to a timestamp
int a[maxn];//Node initial weight
int size[maxn];//The number of subtrees rooted at the point(包括自己
int f[maxn];//前驱
int head[maxn],sign,t;
int n,root,q,mod;
int tree[maxn<<2],lazy[maxn<<2];
struct node
{
int to,p;
}edge[maxn<<1];
void init()
{
for(int i=0;i<=n;i++) head[i]=-1;
sign=t=0;
}
void add(int u,int v)
{
edge[sign]=node{v,head[u]};
head[u]=sign++;
}
void dfs1(int u,int pre,int dep)
{
f[u]=pre;
d[u]=dep;
size[u]=1;
for(int i=head[u];~i;i=edge[i].p)
{
int v=edge[i].to;
if(v==pre) continue;
dfs1(v,u,dep+1);
size[u]+=size[v];
if(size[v]>size[son[u]])
son[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
dfn[u]=++t;
tim[t]=u;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];~i;i=edge[i].p)
{
int v=edge[i].to;
if(v!=f[u]&&v!=son[u]) dfs2(v,v);
}
}
void pushup(int i,int l,int r)
{
tree[i]=(tree[lson]+tree[rson])%mod;
}
void pushdown(int i,int l,int r)
{
if(lazy[i])
{
int mid=half;
tree[lson]+=(mid-l+1)*lazy[i];
tree[rson]+=(r-mid)*lazy[i];
lazy[lson]+=lazy[i];
lazy[rson]+=lazy[i];
lazy[i]=0;
}
}
void build(int i,int l,int r)
{
if(l==r)
{
tree[i]=a[tim[l]];
return;
}
int mid=half;
build(Lson);
build(Rson);
pushup(myself);
}
void update(int i,int l,int r,int ql,int qr,int val)
{
if(ql<=l&&qr>=r)
{
tree[i]+=val*(r-l+1);
lazy[i]+=val;
return;
}
int mid=half;
pushdown(myself);
if(qr<=mid) update(Lson,ql,qr,val);
else if(ql>mid) update(Rson,ql,qr,val);
else update(Lson,ql,mid,val),update(Rson,mid+1,qr,val);
pushup(myself);
}
int query(int i,int l,int r,int ql,int qr)
{
if(ql<=l&&qr>=r) return tree[i]%mod;
pushdown(myself);
int mid=half;
if(qr<=mid) return query(Lson,ql,qr);
else if(ql>mid) return query(Rson,ql,qr);
else return query(Lson,ql,mid)+query(Rson,mid+1,qr);
}
void solve1(int x,int y,int val)//把x,yThe simple path to addval,解释如下
{
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]]) swap(x,y);
update(1,1,n,dfn[top[x]],dfn[x],val);
x=f[top[x]];
}
if(d[x]>d[y]) swap(x,y);
update(1,1,n,dfn[x],dfn[y],val);
}
int solve2(int x,int y)
{
int ans=0;
while(top[x]!=top[y])//当两个点不在同一条链上
{
if(d[top[x]]<d[top[y]]) swap(x,y);//把xDefined as a point with a relatively deep depth,Let him jump up
ans=(ans+query(1,1,n,dfn[top[x]],dfn[x]))%mod;//ans加上x点到x所在链顶端 这一段区间的点权和
x=f[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
}
if(d[x]>d[y]) swap(x,y);//At this point two o'clock is on a chain
ans=(ans+query(1,1,n,dfn[x],dfn[y]))%mod;//A chain is a direct interval sum
return ans;
}
void solve3(int x,int val)//put that point
{
update(1,1,n,dfn[x],dfn[x]+size[x]-1,val);
}
int solve4(int x)
{
return query(1,1,n,dfn[x],dfn[x]+size[x]-1)%mod;
}
int main()
{
// freopen("E://testdata.in","r",stdin);
// freopen("E://1.out","w",stdout);
cin>>n>>q>>root>>mod;
init();
int x,y,op,val;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]=a[i]%mod;
for(int i=1;i<n;i++)
scanf("%d %d",&x,&y),add(x,y),add(y,x);
dfs1(root,0,1);
dfs2(root,root);
build(1,1,n);
while(q--)
{
scanf("%d",&op);
if(op==1) {scanf("%d %d %d",&x,&y,&val);solve1(x,y,val%mod);}
else if(op==2) {scanf("%d %d",&x,&y);printf("%d\n",solve2(x,y));}
else if(op==3) {scanf("%d %d",&x,&val);solve3(x,val%mod);}
else {scanf("%d",&x);printf("%d\n",solve4(x));}
}
}
边栏推荐
- RK3568商显版开源鸿蒙板卡产品解决方案
- 找不到和chrome浏览器版本不同的chromedriver的解决方法
- 【MySQL】update mysql.user set authentication_string=password(“123456“) where User=‘root‘; 报错
- Lottie系列一:介绍与使用
- (本章节完结)排序第五节——非比较排序(计数排序+基数排序+桶排序)(附有自己的视频讲解)
- Forest Program dfs+tanjar仙人掌
- 子路由及路由出口配置
- sklearn数据预处理
- 常用测试用例设计方法之正交实验法详解
- 2017 G icpc shenyang Infinite Fraction Path BFS + pruning
猜你喜欢
随机推荐
P7 Alibaba Interview Questions 2020.07 Sliding Window Algorithm (Alibaba Cloud Interview)
P7阿里面试题2020.07 之滑动窗算法(阿里云面试)
排序第三节——交换排序(冒泡排序+快速排序+快排的优化)(5个视频讲解)
vlucas/phpdotenv phpdotenv获取变量内容偶尔出现返回false
car-price-deeplearning-0411
【sqlite3】sqlite3.OperationalError: table addresses has 7 columns but 6 values were supplied
入门cv必读的10篇baseline论文
顺序表删除所有值为e的元素
物理层课后作业
01 自然语言处理NLP介绍
2017.10.26模拟 b energy
way of thinking problem-solving skills
买口罩(0-1背包)
【报错】Root Cause com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
找出数组中不重复的值php
Pytorch 训练技巧
Colors that Tkinter can choose from
codeforces Valera and Elections (这思维题是做不明白了)
The maximum validity period of an SSL certificate is 13 months. Is it necessary to apply for multiple years at a time?
ByteDance Written Exam 2020 (Douyin E-commerce)