標籤:blog 資料 org define log https change 需要 mod
P3384 【模板】樹鏈剖分題目描述
如題,已知一棵包含N個結點的樹(連通且無環),每個節點上包含一個數值,需要支援以下操作:
操作1: 格式: 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z
操作2: 格式: 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和
操作3: 格式: 3 x z 表示將以x為根節點的子樹內所有節點值都加上z
操作4: 格式: 4 x 表示求以x為根節點的子樹內所有節點值之和
輸入輸出格式
輸入格式:
第一行包含4個正整數N、M、R、P,分別表示樹的結點個數、操作個數、根節點序號和模數數(即所有的輸出結果均對此模數)。
接下來一行包含N個非負整數,分別依次表示各個節點上初始的數值。
接下來N-1行每行包含兩個整數x、y,表示點x和點y之間連有一條邊(保證無環且連通)
接下來M行每行包含若干個正整數,每行表示一個操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x
輸出格式:
輸出包含若干行,分別依次表示每個操作2或操作4所得的結果(對P模數)
輸入輸出範例輸入範例#1:
5 5 2 247 3 7 8 0 1 21 53 14 13 4 23 2 24 51 5 1 32 1 3
輸出範例#1:
221
說明
時空限制:1s,128M
資料規模:
對於30%的資料:N<=10,M<=10
對於70%的資料:N<=1000,M<=1000
對於100%的資料:N<=100000,M<=100000
(其實,純隨機產生的樹LCA+暴力是能過的,可是,你覺得可能是純隨機的麼233)
範例說明:
樹的結構如下:
各個操作如下:
故輸出應依次為2、21(重要的事情說三遍:記得模數)
弱弱的調了1個小時的樹鏈剖分裸題
#include<cstdio>#include<iostream>#define lc k<<1#define rc k<<1|1using namespace std;const int N=1e5+10;const int M=N<<2;struct node{ int v,next;}e[N<<1];int tot,cnt;int n,m,rt,mod,head[N],dep[N],top[N],siz[N],dfn[N],son[N],fa[N],id[N],val[N];int a[M],tag[M];void add(int x,int y){ e[++tot]=(node){y,head[x]}; head[x]=tot;}void dfs(int x,int f,int de){ fa[x]=f;dep[x]=de;siz[x]=1; for(int i=head[x];i;i=e[i].next){ int v=e[i].v; if(v!=f){ dfs(v,x,de+1); siz[x]+=siz[v]; if(!son[x]||siz[son[x]]<siz[v]) son[x]=v; } }}void getpos(int x,bool hson){ if(hson) top[x]=top[fa[x]]; else top[x]=x; id[x]=++cnt; dfn[cnt]=x; if(son[x]) getpos(son[x],1); for(int i=head[x];i;i=e[i].next){ int v=e[i].v; if(v!=fa[x]&&v!=son[x]){ getpos(v,0); } }}void build(int k,int l,int r){ if(l==r){ a[k]=val[dfn[l]]; return ; } int mid=l+r>>1; build(lc,l,mid); build(rc,mid+1,r); a[k]=a[lc]+a[rc];}void pushdown(int k,int l,int r){ if(!tag[k]) return ; int mid=l+r>>1; a[lc]=(a[lc]+(mid-l+1)*tag[k])%mod; a[rc]=(a[rc]+(r-mid)*tag[k])%mod; tag[lc]+=tag[k]; tag[rc]+=tag[k]; tag[k]=0;}void change(int k,int l,int r,int x,int y,int w){ if(l==x&&y==r){ a[k]=(a[k]+(r-l+1)*w)%mod; tag[k]+=w; return ; } pushdown(k,l,r); int mid=l+r>>1; if(y<=mid) change(lc,l,mid,x,y,w); else if(x>mid) change(rc,mid+1,r,x,y,w); else change(lc,l,mid,x,mid,w),change(rc,mid+1,r,mid+1,y,w); a[k]=a[lc]+a[rc];}int query(int k,int l,int r,int x,int y){ if(l==x&&r==y) return a[k]%mod; pushdown(k,l,r); int mid=l+r>>1; if(y<=mid) return query(lc,l,mid,x,y); else if(x>mid) return query(rc,mid+1,r,x,y); else return (query(lc,l,mid,x,mid)+query(rc,mid+1,r,mid+1,y))%mod;}void varylist(int x,int y,int w){ for(;top[x]!=top[y];x=fa[top[x]]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); change(1,1,n,id[top[x]],id[x],w); } if(dep[x]<dep[y]) swap(x,y); change(1,1,n,id[y],id[x],w);}int findlist(int x,int y){ int ans=0; for(;top[x]!=top[y];x=fa[top[x]]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); ans=(ans+query(1,1,n,id[top[x]],id[x]))%mod; } if(dep[x]<dep[y]) swap(x,y); ans=(ans+query(1,1,n,id[y],id[x]))%mod; return ans;} int main(){ scanf("%d%d%d%d",&n,&m,&rt,&mod); for(int i=1;i<=n;i++) scanf("%d",&val[i]); for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x); dfs(rt,rt,1); getpos(rt,0); build(1,1,n); for(int i=1,opt,x,y,z;i<=m;i++){ scanf("%d",&opt); if(opt==1){ scanf("%d%d%d",&x,&y,&z); varylist(x,y,z); } else if(opt==2){ scanf("%d%d",&x,&y); printf("%d\n",findlist(x,y)); } else if(opt==3){ scanf("%d%d",&x,&z); change(1,1,n,id[x],id[x]+siz[x]-1,z); } else if(opt==4){ scanf("%d",&x); printf("%d\n",query(1,1,n,id[x],id[x]+siz[x]-1)); } } return 0;}
P3384 【模板】樹鏈剖分