Foreword
This question is to write write for a long time .. of course, we are in tune ..
Finally found the tree line
build(1,n,1)
writtenbuild(1,1,n)
.. then .. then I want to write notes to learn it.
There is of course part of the reason I have not updated the blog for a long time
Segment tree
So does the tree line where to go .
About my tree line:
build(int l,int r,int k) 建树,到[l,r],下标k void pushdown(int l,int r,int k) 懒标记下传 int query(int l,int r,int x,int y,int k) 查询[x,y]的和,递归到[l,r],下标为k void add(int l,int r,int x,int y,int z,int k) 把[x,y]中每个数加上z,递归到[l,r],下标k
For nothing
As the name suggests, the tree as a chain
Some non-humanOperations, such as query and modify .Then in the sequence, the fast interval plus and range queries , which use the tree line.
For example, in Los template Valley 3384 , we should support four operations:
1. The tree from \ (X \) to \ (Y \) values of all nodes in the shortest path are nodes plus \ (Z \)
2. From the tree request \ (X \) to \ (\ Y) values of all nodes in the shortest path nodes and
3. will \ (X \) is the value of all the nodes within the subtree root node are coupled \ (Z \)
4. In seeking \ (X \) all values within the nodes of the subtree root node and
concept
Weight (zhòng) son : for in addition to the leaf node point other than in its son neutron nodes most is its heavy son.
For example :( heavy son with \ (son [] \) expressed)
Heavy side : to link the two sons of the heavy side. For the rest of the side, called the light side.
Heavy chain : Many multiple edges together, form chains called heavy chains.
E.g:
achieve
So, we can run a the DFS , find each non-leaf node of heavy son .
int dfs1(int x,int pre,int dep) { deep[x]=dep; fa[x]=pre; tot[x]=1; //以x为根节点的子树的大小 int maxson=-1; for(int i=f[x];i;i=e[i].nx) { if(e[i].v==pre)continue; tot[x]+=dfs1(e[i].v,x,dep+1); //更新重儿子↓ if(tot[e[i].v]>maxson){maxson=tot[e[i].v];son[x]=e[i].v;} } return tot[x]; }
Next, we need to put a point in the sequence.
Then there dfs sequence , also ran a dfs.
However, in order respectively so that each point on the heavy chain on consecutive dfs sequence , plus a few statements at dfs:
With \ (top [x] \) Remember the head of the heavy chain of x where, if not in the heavy chain (light side), denoted by himself.
Every start and re-son
Implementation is very short:
void dfs2(int x,int tops) { idx[x]=++cnt; //记录x在序列中的位置 top[x]=tops; a[cnt]=pw[x]; //pw[]为初始每个点的权值 cnt[]就是dfs序 if(!son[x])return; dfs2(son[x],tops); //先跑重儿子 for(int i=f[x];i;i=e[i].nx) //其他轻边 { if(idx[e[i].v])continue; dfs2(e[i].v,e[i].v); } }
Next, we must deal with \ (4 \) kinds of operations. Look behind \ (2 \) species.
3. will \ (X \) is the value of all the nodes within the subtree root node are coupled \ (Z \)
4. In seeking \ (X \) all values within the nodes of the subtree root node and
Obviously, any node x and all its child nodes must appear in consecutive order in dfs . Then these two operations can be handled directly segment tree.
Then the first \ (2 \) operations it?
1.将树从 \(x\) 到 \(y\) 结点最短路径上所有节点的值都加上 \(z\)
2.求树从 \(x\) 到 \(y\) 结点最短路径上所有节点的值之和
从\(x\)到\(y\)的最短路径只有一条,那么在在这条路径中,要在dfs序上加多少个区间?
按照之前的定义,重链上的点一定连续出现在dfs序上,所以,我们可以把 \(x\) , \(y\) 往上跳,即 \(x=top[x],y=top[y]\) , 直到 \(top[x]==top[y]\) 的时候停下来。
然后每次跳的时候,相应处理序列的值。
要注意的是,每次跳时,应选择重链的头更深的跳。
画图举例:
结束√
实现:
void treeadd(int x,int y,int val)//操作3 { while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]])swap(x,y); add(1,n,idx[top[x]],idx[x],val,1); x=fa[top[x]]; } if(deep[x]>deep[y])swap(x,y); add(1,n,idx[x],idx[y],val,1); }
int treesum(int x,int y)//操作4 { int ans=0; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]])swap(x,y); ans=(ans+query(1,n,idx[top[x]],idx[x],1))%Mod; x=fa[top[x]]; } if(deep[x]>deep[y])swap(x,y); ans=(ans+query(1,n,idx[x],idx[y],1))%Mod; return ans; }
时间复杂度
有\(2\)个性质:
若边 \((x,fa)\) 为轻边,则 \(size(x) \le \frac{size(u)}{2}\)
树中任意 \(2\) 个节点之间的路径中,轻边不超过 \(log_2 n\),重链不超过 \(log_2 n\)
在算上线段树复杂度 \(O(log^2 n)\)
- 完整代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int Maxn=1e5+5;
struct edge{
int v,nx;
}e[Maxn<<1];
struct tree{
int sum,lazy;
}t[Maxn<<2];
int n,m,ne,root,Mod,f[Maxn],pw[Maxn];
int deep[Maxn],fa[Maxn],son[Maxn],tot[Maxn];//dfs1
int cnt,top[Maxn],idx[Maxn],a[Maxn];//dfs2
void addedge(int u,int v)
{
e[++ne].v=v;
e[ne].nx=f[u];
f[u]=ne;
}
int dfs1(int x,int pre,int dep)
{
deep[x]=dep;
fa[x]=pre;
tot[x]=1;
int maxson=-1;
for(int i=f[x];i;i=e[i].nx)
{
if(e[i].v==pre)continue;
tot[x]+=dfs1(e[i].v,x,dep+1);
if(tot[e[i].v]>maxson){maxson=tot[e[i].v];son[x]=e[i].v;}
}
return tot[x];
}
void dfs2(int x,int tops)
{
idx[x]=++cnt;
top[x]=tops;
a[cnt]=pw[x];
if(!son[x])return;
dfs2(son[x],tops);
for(int i=f[x];i;i=e[i].nx)
{
if(idx[e[i].v])continue;
dfs2(e[i].v,e[i].v);
}
}
void build(int l,int r,int k)
{
if(l==r)
{ t[k].sum=a[l];t[k].lazy=0;
return;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
t[k].sum=(t[k<<1].sum+t[k<<1|1].sum)%Mod;
t[k].lazy=0;
}
void pushdown(int l,int r,int k)
{
int mid=(l+r)>>1;
int x=t[k].lazy;
t[k<<1].sum=(t[k<<1].sum+(mid-l+1)*x)%Mod;
t[k<<1|1].sum=(t[k<<1|1].sum+(r-mid)*x)%Mod;
t[k<<1].lazy=(t[k<<1].lazy+x)%Mod;
t[k<<1|1].lazy=(t[k<<1|1].lazy+x)%Mod;
t[k].lazy=0;
}
int query(int l,int r,int x,int y,int k)
{
if(x<=l&&r<=y)return t[k].sum;
pushdown(l,r,k);
int mid=(l+r)>>1;
if(y<=mid)return query(l,mid,x,y,k<<1);
if(x>mid)return query(mid+1,r,x,y,k<<1|1);
return (query(l,mid,x,y,k<<1)+query(mid+1,r,x,y,k<<1|1))%Mod;
}
void add(int l,int r,int x,int y,int z,int k)
{
if(x<=l&&r<=y)
{
t[k].sum=(t[k].sum+(r-l+1)*z)%Mod;
t[k].lazy=(t[k].lazy+z)%Mod;;
return;
}
pushdown(l,r,k);
int mid=(l+r)>>1;
if(x<=mid)add(l,mid,x,y,z,k<<1);
if(y>mid)add(mid+1,r,x,y,z,k<<1|1);
t[k].sum=(t[k<<1].sum+t[k<<1|1].sum)%Mod;
}
void treeadd(int x,int y,int val)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])swap(x,y);
add(1,n,idx[top[x]],idx[x],val,1);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
add(1,n,idx[x],idx[y],val,1);
}
int treesum(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])swap(x,y);
ans=(ans+query(1,n,idx[top[x]],idx[x],1))%Mod;
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
ans=(ans+query(1,n,idx[x],idx[y],1))%Mod;
return ans;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&root,&Mod);
for(int i=1;i<=n;i++)
scanf("%d",&pw[i]);
for(int i=1;i<=n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs1(root,0,1);//找重儿子
dfs2(root,root);//求序列
build(1,n,1);//线段树
while(m--)
{
int opt,x,y,z;
scanf("%d",&opt);
if(opt==1)
{
scanf("%d%d%d",&x,&y,&z);
treeadd(x,y,z);
}
if(opt==2)
{
scanf("%d%d",&x,&y);
printf("%d\n",treesum(x,y));
}
if(opt==3)
{
scanf("%d%d",&x,&y);
add(1,n,idx[x],idx[x]+tot[x]-1,y%Mod,1);
}
if(opt==4)
{
scanf("%d",&x);
printf("%d\n",query(1,n,idx[x],idx[x]+tot[x]-1,1));
}
}
return 0;
}
\[\text{by Rainy7}\]