1. 程式人生 > 實用技巧 >樹鏈剖分_[模板]

樹鏈剖分_[模板]

題目連結洛谷P3374 【模板】輕重鏈剖分
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
struct node{
    int a,lz;
}tree[200000];
int v[200000],w[200000],next[200000],last[200000],num,nw[200000],id[200000];
int son[200000],top[200000],deep[200000],size[200000],fa[200000];
int n,m,r,p;
void add(int x,int y) { num++; v[num]=y; next[num]=last[x]; last[x]=num; } void dfs1(int root,int ff,int de) { fa[root]=ff; deep[root]=de; size[root]=1; int maxson=0; for(int i=last[root];i;i=next[i]) { if(deep[v[i]]!=0) continue; dfs1(v[i],root,de
+1); size[root]+=size[v[i]]; if(size[v[i]]>maxson) son[root]=v[i]; } } void dfs2(int root,int topp) { num++; top[root]=topp; nw[num]=w[root]; id[root]=num; if(son[root]!=0) dfs2(son[root],topp); for(int i=last[root];i;i=next[i]) { if (top[v[i]]!=0
) continue; dfs2(v[i],v[i]); } } void buildtree(int root,int l,int r) { if(l>r) return; if(l==r){ tree[root].a=nw[l]; return;} int mid=(r+l)/2; buildtree(root*2,l,mid); buildtree(root*2+1,mid+1,r); tree[root].a=(tree[root*2].a+tree[root*2+1].a)%p; } void putdown(int root,int l,int r) { if(tree[root].lz!=0) { tree[root*2].lz+=tree[root].lz; tree[root*2+1].lz+=tree[root].lz; int mid=(l+r)/2; tree[root*2].a=(tree[root*2].a%p+tree[root].lz*(mid-l+1)%p)%p; tree[root*2+1].a=(tree[root*2+1].a%p+tree[root].lz*(r-mid)%p)%p; tree[root].lz=0; } return; } void treechange(int root,int l,int r,int s,int t,int ad) { if(s<=l && r<=t) { tree[root].lz+=ad; tree[root].a=(tree[root].a+(r-l+1)*ad)%p; return; } putdown(root,l,r); int mid=(l+r)/2; if (mid>=s) treechange(root*2,l,mid,s,t,ad); if (mid+1<=t) treechange(root*2+1,mid+1,r,s,t,ad); tree[root].a=(tree[root*2].a+tree[root*2+1].a)%p; return; } int treefind(int root,int l,int r,int s,int t) { if(l>=s && r<=t) return tree[root].a; if(r<s || l>t) return 0; putdown(root,l,r); int ans=0,mid=(l+r)/2; if(mid>=s) ans=(ans%p+treefind(root*2,l,mid,s,t)%p)%p; if(mid+1<=t) ans=(ans%p+treefind(root*2+1,mid+1,r,s,t)%p)%p; return ans%p; } void change1(int x,int y,int z) { while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) swap(x,y); treechange(1,1,n,id[top[x]],id[x],z); x=fa[top[x]]; } if(deep[x]<deep[y]) swap(x,y); treechange(1,1,n,id[y],id[x],z); } int find1(int x,int y,int z) { int ans=0; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) swap(x,y); ans=(ans+treefind(1,1,n,id[top[x]],id[x]))%p; x=fa[top[x]]; } if(deep[x]<deep[y]) swap(x,y); ans=(ans+treefind(1,1,n,id[y],id[x]))%p; return ans; } void change2(int x,int z){ treechange(1,1,n,id[x],id[x]+size[x]-1,z); } int find2(int x){ int ans=0; ans=treefind(1,1,n,id[x],id[x]+size[x]-1)%p; return ans; } int main() { scanf("%d%d%d%d",&n,&m,&r,&p); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<=n-1;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs1(r,0,1); num=0; dfs2(r,r); buildtree(1,1,n); for(int i=1;i<=m;i++) { int t,x,y,z; scanf("%d",&t); if(t==1) { scanf("%d%d%d",&x,&y,&z); change1(x,y,z); } if(t==2) { scanf("%d%d",&x,&y); int ans=find1(x,y,z); printf("%d\n",ans%p); } if(t==3) { scanf("%d%d",&x,&z); change2(x,z); } if(t==4) { scanf("%d",&x); int ans=find2(x); printf("%d\n",ans%p); } } }