【loj#139】樹鏈剖分
#139. 樹鏈剖分
題目描述
這是一道模板題。
給定一棵 $n$個節點的樹,初始時該樹的根為 111 號節點,每個節點有一個給定的權值。下面依次進行 $m$ 個操作,操作分為如下五種型別:
-
換根:將一個指定的節點設定為樹的新根。
-
修改路徑權值:給定兩個節點,將這兩個節點間路徑上的所有節點權值(含這兩個節點)增加一個給定的值。
-
修改子樹權值:給定一個節點,將以該節點為根的子樹內的所有節點權值增加一個給定的值。
-
詢問路徑:詢問某條路徑上節點的權值和。
-
詢問子樹:詢問某個子樹內節點的權值和
輸入格式
第一行為一個整數 n,表示節點的個數。
第二行 n 個整數表示第 iii 個節點的初始權值 $a_i$。
第三行 n−1 個整數,表示 i+1i+1i+1 號節點的父節點編號$ fi+1 (1⩽fi+1⩽n)f_{i+1}\ (1 \leqslant f_{i+1} \leqslant n)fi+1 (1⩽fi+1⩽n)。$
第四行一個整數 m,表示操作個數。
接下來 m 行,每行第一個整數表示操作型別編號:$(1⩽u,v⩽n)(1 \leqslant u, v \leqslant n)(1⩽u,v⩽n)$
-
若型別為 111,則接下來一個整數 u,表示新根的編號。
-
若型別為 222,則接下來三個整數 u,v,ku,v,ku,v,k,分別表示路徑兩端的節點編號以及增加的權值。
-
若型別為 333,則接下來兩個整數 u,ku,ku,k,分別表示子樹根節點編號以及增加的權值。
-
若型別為 444,則接下來兩個整數 u,vu,vu,v,表示路徑兩端的節點編號。
-
若型別為 555,則接下來一個整數 u,表示子樹根節點編號。
輸出格式
對於每一個型別為 444 或 555 的操作,輸出一行一個整數表示答案。
樣例
樣例輸入
6
1 2 3 4 5 6
1 2 1 4 4
6
4 5 6
2 2 4 1
5 1
1 4
3 1 2
4 2 5
樣例輸出
15
24
19
資料範圍與提示
對於 $100%100\%100%$ 的資料,$1⩽n,m,k,ai⩽1051\leqslant n,m,k,a_i\leqslant 10^51⩽n,m,k,ai⩽105$。資料有一定梯度。
題意:樹鏈加,子樹加,需要支援換根,查詢樹鏈和,子樹和
題解:
樹鏈剖分模板,樹鏈加和查詢直接樹鏈剖分即可,
注意到樹鏈剖分有個很方便的性質就是鏈剖的序列其實也是dfs序,記錄一個點的序列上起點和終點就可以順便維護子樹,
換根的話分類討論一下,一直以1號點為根,對樹鏈的修查無影響,考慮子樹:
假設訪問u號點,在以1號點為根的形態下:
當前根rt,如果u==rt則u的子樹為整個以1為根的樹,
如果rt是u的子樹裡的節點,那麼u所代表的的子樹就是整個子樹 - rt的祖先裡u的兒子的 子樹 ,
如果rt不是u的子樹裡的節點,那麼u的子樹就是以1為根時u的子樹;
這樣操作後也是區間,可以和前兩個一起維護;
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<queue> 6 #include<cmath> 7 #include<vector> 8 #include<stack> 9 #include<map> 10 #define ls (k<<1) 11 #define rs (k<<1|1) 12 #define Run(i,l,r) for(int i=l;i<=r;i++) 13 #define Don(i,l,r) for(int i=l;i>=r;i--) 14 #define ll long long 15 #define inf 0x3f3f3f3f 16 using namespace std; 17 const int N=100010; 18 int n,m,o,hd[N],tp[N],st[N],ed[N],idx,son[N],fa[N],w[N],sz[N],dep[N],root;// 19 ll val[N],sum[N<<2],ly[N<<2];// 20 struct Edge{int v,nt;}E[N<<1]; // 21 char gc(){ 22 static char*p1,*p2,s[1000000]; 23 if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); 24 return(p1==p2)?EOF:*p1++; 25 }// 26 int rd(){ 27 int x=0,f=1; char c=gc(); 28 while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc();} 29 while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0',c=gc();} 30 return x*f; 31 }// 32 void adde(int u,int v){ 33 E[o]=(Edge){v,hd[u]};hd[u]=o++; 34 E[o]=(Edge){u,hd[v]};hd[v]=o++; 35 }// 36 void dfsA(int u,int F){ 37 dep[u]=dep[F]+1; 38 son[u]=0; sz[u]=1; 39 for(int i=hd[u];~i;i=E[i].nt){ 40 int v=E[i].v; 41 if(v==F)continue; 42 dfsA(v,u); 43 sz[u]+=sz[v]; 44 if(sz[v]>sz[son[u]])son[u]=v; 45 } 46 }// 47 void dfsB(int u,int T){ 48 tp[u]=T; val[st[u]=++idx]=w[u]; 49 if(son[u])dfsB(son[u],T); 50 for(int i=hd[u];~i;i=E[i].nt){ 51 int v=E[i].v; 52 if(v==son[u]||v==fa[u])continue; 53 dfsB(v,v); 54 } 55 ed[u]=idx; 56 }// 57 void pushup(int k){sum[k]=sum[ls]+sum[rs];}// 58 void mfy(int k,int l,int r,ll v){sum[k]+=v*(r-l+1);ly[k]+=v;}// 59 void pushdown(int k,int l,int r){ 60 if(ly[k]){ 61 int mid=(l+r)>>1; 62 mfy(ls,l,mid,ly[k]); 63 mfy(rs,mid+1,r,ly[k]); 64 ly[k]=0; 65 } 66 }// 67 void build(int k,int l,int r){ 68 if(l==r){sum[k]=val[l];ly[k]=0;return;} 69 int mid=(l+r)>>1; 70 build(ls,l,mid); 71 build(rs,mid+1,r); 72 pushup(k); 73 }// 74 void update(int k,int l,int r,int x,int y,ll v){ 75 if(l==x&&r==y)mfy(k,l,r,v); 76 else { 77 pushdown(k,l,r); 78 int mid=(l+r)>>1; 79 if(y<=mid)update(ls,l,mid,x,y,v); 80 else if(x>mid)update(rs,mid+1,r,x,y,v); 81 else update(ls,l,mid,x,mid,v) , update(rs,mid+1,r,mid+1,y,v); 82 pushup(k); 83 } 84 }// 85 ll query(int k,int l,int r,int x,int y){ 86 if(l==x&&r==y)return sum[k]; 87 else { 88 pushdown(k,l,r); 89 int mid=(l+r)>>1; 90 if(y<=mid)return query(ls,l,mid,x,y); 91 else if(x>mid)return query(rs,mid+1,r,x,y); 92 else return query(ls,l,mid,x,mid) + query(rs,mid+1,r,mid+1,y); 93 } 94 }// 95 int child(int u,int v){ 96 while(tp[u]!=tp[v]){ 97 u=tp[u]; 98 if(fa[u]==v)return u; 99 u=fa[u]; 100 } 101 return son[v]; 102 }// 103 void update1(int u,int v,int x){ 104 while(tp[u]!=tp[v]){ 105 if(dep[tp[u]]<dep[tp[v]])swap(u,v); 106 update(1,1,n,st[tp[u]],st[u],x); 107 u=fa[tp[u]]; 108 } 109 if(dep[u]<dep[v])swap(u,v); 110 update(1,1,n,st[v],st[u],x); 111 }// 112 void update2(int u,int x){ 113 if(u==root){update(1,1,n,1,n,x);} 114 else if(st[u]<=st[root]&&ed[root]<=ed[u]){ 115 int t = child(root,u); 116 update(1,1,n,1,n,x); 117 update(1,1,n,st[t],ed[t],-x); 118 } 119 else{update(1,1,n,st[u],ed[u],x);} 120 }// 121 void query1(int u,int v){ 122 ll ret=0; 123 while(tp[u]!=tp[v]){ 124 if(dep[tp[u]]<dep[tp[v]])swap(u,v); 125 ret += query(1,1,n,st[tp[u]],st[u]); 126 u=fa[tp[u]]; 127 } 128 if(dep[u]<dep[v])swap(u,v); 129 ret += query(1,1,n,st[v],st[u]); 130 printf("%lld\n",ret); 131 }// 132 void query2(int u){ 133 ll ret=0; 134 if(u==root)ret=query(1,1,n,1,n); 135 else if(st[u]<=st[root]&&ed[root]<=ed[u]){ 136 int t = child(root,u); 137 ret += query(1,1,n,1,n); 138 ret -= query(1,1,n,st[t],ed[t]); 139 } 140 else{ret = query(1,1,n,st[u],ed[u]);} 141 printf("%lld\n",ret); 142 }// 143 int main(){ 144 //freopen("loj139.in","r",stdin); 145 //freopen("loj139.out","w",stdout); 146 n=rd(); 147 for(int i=1;i<=n;i++)w[i]=rd(),hd[i]=-1; 148 for(int i=2;i<=n;i++)adde(fa[i]=rd(),i); 149 dfsA(root=1,0);dfsB(1,1); 150 build(1,1,n); 151 m=rd(); 152 for(int i=1,u,v,x;i<=m;i++){ 153 int op=rd(); 154 if(op==1)root=rd(); 155 else if(op==2){u=rd();v=rd();x=rd();update1(u,v,x);} 156 else if(op==3){u=rd();x=rd();update2(u,x);} 157 else if(op==4){u=rd();v=rd();query1(u,v);} 158 else {u=rd();query2(u);} 159 } 160 return 0; 161 }//by tkys_Austin;View Code