#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define LL long long #define l(x) (x<<1) #define r(x) ((x<<1)|1) using namespace std; struct EDG { int to,nex; }es[1000010]; int n,m,r,p; int first[100010]; int cnt; void link(int a,int b) { es[++cnt].nex=first[a]; first[a]=cnt; es[cnt].to=b; } LL a[1000100]; //树剖↓ LL real[1000010],sid[1000010],hson[1000010],fa[1000010],dep[1000010],size[1000010],top[1000010]; LL tot; void dfs1(int x) { size[x]=1; for(int i=first[x];i;i=es[i].nex) { int v=es[i].to; if(v!=fa[x]) { fa[v]=x; dep[v]=dep[x]+1; dfs1(v); if(hson[x]==0||size[hson[x]]<size[v]) { hson[x]=v; } size[x]+=size[v]; } } } void dfs2(int x,int anc) { top[x]=anc; sid[x]=++tot; real[tot]=x; if(hson[x]==0) return; dfs2(hson[x],anc); for(int i=first[x];i;i=es[i].nex) { int v=es[i].to; if(v!=hson[x]&&v!=fa[x]) { dfs2(v,v); } } } //树剖↑ //线段树 ↓ struct Tre { LL sum,tag; }Tr[1000100]; void update(LL id) { Tr[id].sum=Tr[l(id)].sum+Tr[r(id)].sum; } void pushdown(LL l,LL r,LL id) { Tr[r(id)].tag+=Tr[id].tag; Tr[l(id)].tag+=Tr[id].tag; Tr[id].sum+=(r-l+1)*Tr[id].tag; Tr[id].tag=0; } void build(LL l,LL r,LL id) { if(l==r) { Tr[id].sum=a[real[l]]; return; } LL mid=(l+r)/2; build(mid+1,r,r(id)); build(l,mid,l(id)); update(id); } void add(LL al,LL ar,LL x,LL l,LL r,LL id) { if(l>ar||r<al) return; if(al==l&&ar==r) {Tr[id].tag+=x;return;} pushdown(l,r,id); LL mid=(r+l)/2; if(mid>=al) add(al,min(mid,ar),x,l,mid,l(id)); if(mid<ar) add(max(mid+1,al),ar,x,mid+1,r,r(id)); pushdown(l,mid,l(id)); pushdown(mid+1,r,r(id)); update(id); } LL query(LL al,LL ar,LL l,LL r,LL id) { if(l>r) return 0LL; if(al==l&&ar==r) {return Tr[id].tag*(r-l+1)+Tr[id].sum;} pushdown(l,r,id); LL mid=(r+l)/2; LL t=0; if(mid>=al) t+=query(al,min(mid,ar),l,mid,l(id)); if(mid<ar) t+=query(max(mid+1,al),ar,mid+1,r,r(id)); return t; } //线段树 ↑ //树剖用线段树维护↓ void tr_add(LL x,LL v)//x点及其子孙权值加v { add(sid[x],sid[x]+size[x]-1,v,1,n,1); } LL tr_query(LL x)//x点及其子孙权值和 { return query(sid[x],sid[x]+size[x]-1,1,n,1)%p; } LL chain_add(LL x,LL y,LL v)//x到y的链上每个点加v { LL tx,ty; tx=top[x];ty=top[y]; while(tx!=ty) { if(dep[tx]<dep[ty]) { swap(x,y); swap(tx,ty); } add(sid[tx],sid[x],v,1,n,1); x=fa[tx];tx=top[x]; } if(dep[x]<dep[y]) swap(x,y); add(sid[y],sid[x],v,1,n,1); } LL chain_query(LL x,LL y)//查询x到y的链上权值和 { LL tx,ty,t=0; tx=top[x];ty=top[y]; while(tx!=ty) { if(dep[tx]<dep[ty]) {swap(tx,ty);swap(x,y);} (t+=query(sid[tx],sid[x],1,n,1))%=p; x=fa[tx];tx=top[x]; } if(dep[x]<dep[y]) swap(x,y); (t+=query(sid[y],sid[x],1,n,1))%=p; return t; } //树剖用线段树维护↑ int main() { scanf("%d%d%d%d",&n,&m,&r,&p); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); link(x,y);link(y,x); } dep[r]=1; dfs1(r); dfs2(r,r); build(1,n,1); for(int i=1;i<=m;i++) { int q; scanf("%d",&q); if(q==1) { LL x,y,z; scanf("%lld%lld%lld",&x,&y,&z); chain_add(x,y,z); } if(q==2) { LL x,y; scanf("%lld%lld",&x,&y); cout<<chain_query(x,y); cout<<endl; } if(q==3) { LL x,z; scanf("%lld%lld",&x,&z); tr_add(x,z); } if(q==4) { LL x; scanf("%lld",&x); cout<<tr_query(x); cout<<endl; } } }
原文:http://www.cnblogs.com/wjxgy/p/7834767.html