如題,已知一棵包含N個結點的樹(連通且無環),每一個節點上包含一個數值,須要支持如下操做:html
操做1: 格式: 1 x y z 表示將樹從x到y結點最短路徑上全部節點的值都加上znode
操做2: 格式: 2 x y 表示求樹從x到y結點最短路徑上全部節點的值之和ios
操做3: 格式: 3 x z 表示將以x爲根節點的子樹內全部節點值都加上zapp
操做4: 格式: 4 x 表示求以x爲根節點的子樹內全部節點值之和ui
第一行包含4個正整數N、M、R、P,分別表示樹的結點個數、操做個數、根節點序號和取模數(即全部的輸出結果均對此取模)。spa
接下來一行包含N個非負整數,分別依次表示各個節點上初始的數值。code
接下來N-1行每行包含兩個整數x、y,表示點x和點y之間連有一條邊(保證無環且連通)htm
接下來M行每行包含若干個正整數,每行表示一個操做,格式以下:blog
操做1: 1 x y zit
操做2: 2 x y
操做3: 3 x z
操做4: 4 x
輸出格式:
輸出包含若干行,分別依次表示每一個操做2或操做4所得的結果(對P取模)
時空限制:1s,128M
數據規模:
對於30%的數據: N \leq 10, M \leq 10N≤10,M≤10
對於70%的數據: N \leq {10}^3, M \leq {10}^3N≤103,M≤103
對於100%的數據: N \leq {10}^5, M \leq {10}^5N≤105,M≤105
( 其實,純隨機生成的樹LCA+暴力是能過的,但是,你以爲多是純隨機的麼233 )
樣例說明:
樹的結構以下:
各個操做以下:
故輸出應依次爲二、21(重要的事情說三遍:記得取模)
#include<iostream> #include<cstdio> #include<algorithm> #define N 100010 using namespace std; struct node{int to,pre;}e[N*2]; struct Tree{ int v,lazy; int l,r; }tr[N*3]; int dep[N],sz[N],son[N],fa[N],top[N],w[N]; int wt[N],id[N],head[N]; int n,m,root,mod,ne,res=0,cnt,num; void Insert(int from,int to){ e[++num].to=to; e[num].pre=head[from]; head[from]=num; } void dfs1(int now,int father){ dep[now]=dep[father]+1; fa[now]=father; sz[now]=1; for(int i=head[now];i;i=e[i].pre){ int to=e[i].to; if(to==father)continue; dfs1(to,now); sz[now]+=sz[to]; if(sz[to]>sz[son[now]])son[now]=to; } } void dfs2(int now,int topfather){ id[now]=++cnt; wt[cnt]=w[now]; top[now]=topfather; if(!son[now])return; dfs2(son[now],topfather); for(int i=head[now];i;i=e[i].pre){ int to=e[i].to; if(to==fa[now]||to==son[now])continue; dfs2(to,to); } } void build(int k,int l,int r){ tr[k].l=l;tr[k].r=r; if(l==r){ tr[k].v=wt[l]%mod; return; } int mid=(l+r)>>1; build(k<<1,l,mid);build(k<<1|1,mid+1,r); tr[k].v=(tr[k<<1].v+tr[k<<1|1].v)%mod; } void down(int k){ int vv=tr[k].lazy; tr[k].lazy=0; tr[k<<1].lazy+=vv;tr[k<<1|1].lazy+=vv; tr[k<<1].v=(tr[k<<1].v+vv*(tr[k<<1].r-tr[k<<1].l+1))%mod; tr[k<<1|1].v=(tr[k<<1|1].v+vv*(tr[k<<1|1].r-tr[k<<1|1].l+1))%mod; } void update(int k,int opl,int opr,int opv){ if(tr[k].l>=opl&&tr[k].r<=opr){ tr[k].lazy=(tr[k].lazy+opv)%mod; tr[k].v=(tr[k].v+opv*(tr[k].r-tr[k].l+1))%mod; return; } down(k); int mid=(tr[k].l+tr[k].r)>>1; if(opl<=mid)update(k<<1,opl,opr,opv); if(opr>mid)update(k<<1|1,opl,opr,opv); tr[k].v=(tr[k<<1].v+tr[k<<1|1].v)%mod; } void change1(int x,int y,int opv){ opv%=mod; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); update(1,id[top[x]],id[x],opv); x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); update(1,id[x],id[y],opv); } void query(int k,int opl,int opr){ if(tr[k].l>=opl&&tr[k].r<=opr){ res+=tr[k].v;res%=mod; return; } down(k); int mid=(tr[k].l+tr[k].r)>>1; if(opl<=mid)query(k<<1,opl,opr); if(opr>mid)query(k<<1|1,opl,opr); } int query1(int x,int y){ int ans=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); res=0; query(1,id[top[x]],id[x]); ans+=res;ans%=mod; x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); res=0; query(1,id[x],id[y]); ans+=res;ans%=mod; return ans; } void change2(int x,int opv){ update(1,id[x],id[x]+sz[x]-1,opv); } int query2(int x){ res=0; query(1,id[x],id[x]+sz[x]-1); return res; } int main(){ scanf("%d%d%d%d",&n,&m,&root,&mod); for(int i=1;i<=n;i++)scanf("%d",&w[i]); int x,y,z; for(int i=1;i<n;i++){ scanf("%d%d",&x,&y); Insert(x,y),Insert(y,x); } dep[0]=-1; dfs1(root,0);dfs2(root,root); build(1,1,n); while(m--){ int op; scanf("%d",&op); if(op==1){ scanf("%d%d%d",&x,&y,&z); change1(x,y,z); } else if(op==2){ scanf("%d%d",&x,&y); cout<<query1(x,y)<<endl; } else if(op==3){ scanf("%d%d",&x,&z); change2(x,z); } else { scanf("%d",&x); cout<<query2(x)<<endl; } } return 0; }