树链剖分
What?
熟练泼粪这又是一种十分神奇的数据结构,由于博主认为自身实力不行,所以不敢随便BB,上一个大佬级别的链接,超级清楚!Problem
不随便BB(既然不能随便BB,那只好不随便了)
依本博主看,树链剖分就是将一棵漂亮的树,解剖成一条条树链,然后使用线段树进行维护,从而解决一系列问题。
只要理解了树链剖分中各种新有名词的含义及特点,那么树链剖分便十分的简单。
有同学说:“什么?用线段树维护,那不是很变态?”没错,不过线段树算什么?引某位大佬早上对我说的一句话:“我们要把线段树当成STL来用。”%%%
Code
本博主由于懒,所以没打链式前向星(其实是不会啊),不过vector真好用啊。
#include<cstdio> #include<vector> #include<algorithm> #define MAXN 100010 #define UD unsigned using namespace std; int n,m,r,Mod,cnt,ans; int init[MAXN],cor[MAXN]; UD sl[MAXN]; vector<int> rel[MAXN]; struct CHAIN { int id; int fa; int zhi; int size; int deep; int Max_son; int top; }chain[MAXN]; struct TREE { int l,r; int zhi; int lazy; }tree[MAXN*8]; void Pushdown(int k) { tree[k<<1].zhi+=(tree[k<<1].r-tree[k<<1].l+1)*tree[k].lazy; tree[k<<1].zhi%=Mod; tree[k<<1].lazy+=tree[k].lazy; tree[k<<1].lazy%=Mod; tree[k<<1|1].zhi+=(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].lazy; tree[k<<1|1].zhi%=Mod; tree[k<<1|1].lazy+=tree[k].lazy; tree[k<<1|1].lazy%=Mod; tree[k].lazy=0; } void Build(int L,int R,int k) { int Mid=(L+R)>>1; tree[k].l=L,tree[k].r=R; if(L==R) { tree[k].zhi=chain[cor[L]].zhi%=Mod; return; } Build(L,Mid,k<<1); Build(Mid+1,R,k<<1|1); tree[k].zhi=tree[k<<1].zhi+tree[k<<1|1].zhi; tree[k].zhi%=Mod; } void Update(int L,int R,int k,int s,int t,int x) { int Mid=(L+R)>>1; Pushdown(k); if(s<=L && R<=t) { tree[k].zhi+=(tree[k].r-tree[k].l+1)*x; tree[k].lazy+=x; tree[k].zhi%=Mod; tree[k].lazy%=Mod; return; } if(s<=Mid) Update(L,Mid,k<<1,s,t,x); if(Mid<t) Update(Mid+1,R,k<<1|1,s,t,x); tree[k].zhi=tree[k<<1].zhi+tree[k<<1|1].zhi; tree[k].zhi%=Mod; } void Query(int L,int R,int k,int s,int t) { int Mid=(L+R)>>1; Pushdown(k); if(s<=L && R<=t) { ans+=tree[k].zhi; ans%=Mod; return; } if(s<=Mid) Query(L,Mid,k<<1,s,t); if(Mid<t) Query(Mid+1,R,k<<1|1,s,t); } void Dfs1(int x,int f,int dep) { int MAX=0; chain[x].fa=f,chain[x].deep=dep,chain[x].size=1,chain[x].zhi=init[x]%=Mod; for(UD i=0;i<sl[x];i++) { if(rel[x][i]==chain[x].fa) continue; Dfs1(rel[x][i],x,dep+1); if(chain[rel[x][i]].size>MAX) MAX=chain[rel[x][i]].size,chain[x].Max_son=rel[x][i]; chain[x].size+=chain[rel[x][i]].size; } } void Dfs2(int x,int topf) { chain[x].id=++cnt; cor[cnt]=x,chain[x].top=topf; if(!chain[x].Max_son) return; Dfs2(chain[x].Max_son,topf); for(UD i=0;i<sl[x];i++) { if(rel[x][i]==chain[x].fa || rel[x][i]==chain[x].Max_son) continue; Dfs2(rel[x][i],rel[x][i]); } } void Update_chain(int x,int y,int z) { while(chain[x].top!=chain[y].top) { if(chain[chain[x].top].deep<chain[chain[y].top].deep) swap(x,y); Update(1,n,1,chain[chain[x].top].id,chain[x].id,z); x=chain[chain[x].top].fa; } if(chain[x].deep>chain[y].deep) swap(x,y); Update(1,n,1,chain[x].id,chain[y].id,z); } void Query_chain(int x,int y) { ans=0; while(chain[x].top!=chain[y].top) { if(chain[chain[x].top].deep<chain[chain[y].top].deep) swap(x,y); Query(1,n,1,chain[chain[x].top].id,chain[x].id); x=chain[chain[x].top].fa; } if(chain[x].deep>chain[y].deep) swap(x,y); Query(1,n,1,chain[x].id,chain[y].id); } void Update_tree(int x,int z) <%Update(1,n,1,chain[x].id,chain[x].id+chain[x].size-1,z);%> void Query_tree(int x) { ans=0; Query(1,n,1,chain[x].id,chain[x].id+chain[x].size-1); } int main() { int opt,x,y,z; scanf("%d%d%d%d",&n,&m,&r,&Mod); for(int i=1;i<=n;i++) scanf("%d",&init[i]); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); rel[x].push_back(y); rel[y].push_back(x); } for(int i=1;i<=n;i++) sl[i]=rel[i].size(); Dfs1(r,0,1); Dfs2(r,r); Build(1,n,1); for(int i=1;i<=m;i++) { scanf("%d",&opt); if(opt==1) { scanf("%d%d%d",&x,&y,&z); Update_chain(x,y,z); } if(opt==2) { scanf("%d%d",&x,&y); Query_chain(x,y); printf("%d\n",ans%Mod); } if(opt==3) { scanf("%d%d",&x,&z); Update_tree(x,z); } if(opt==4) { scanf("%d",&x); Query_tree(x); printf("%d\n",ans%Mod); } } return 0; }
码量不过200行+