【bzoj1036/ZJOI2008】树的统计Count——树链剖分套(zkw)线段树
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16
1
2
2
10
6
5
6
5
16
把原来的树链剖后作为线段树的叶子结点,这样保证每条重链上的节点都一定在连续的一段区间内,单点修改直接按照zkw的写法即可,区间查max和sum则要在各自的链上查询直到到了两点跳到了同一条链上,最后再区间查询一次即可,剩下的就是zkw线段树的基本操作了。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 const int N=3e4+10; 5 int n,first[N],tot=0,ai[N],sum=0,ss=0,mx; 6 int mst[N*3][2]; 7 struct node{int ne,to;}e[N*2]; 8 struct point{ 9 int id,fa,son,top,wi,dep,sz; 10 }q[N]; 11 int read(){ 12 int f=1,ans=0;char c=getchar(); 13 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 14 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 15 return ans*f; 16 } 17 int max1(int aa,int bb){return aa>bb?aa:bb;} 18 void ins(int u,int v){e[++tot]=(node){first[u],v};first[u]=tot;} 19 void dfs(int x,int fa){ 20 point&w=q[x];w.sz=1;w.wi=ai[x]; 21 for(int i=first[x];i;i=e[i].ne){ 22 int to=e[i].to; 23 if(to!=fa){ 24 point&u=q[to]; 25 u.dep=w.dep+1;u.fa=x;dfs(to,x);w.sz+=u.sz; 26 if(q[w.son].sz<u.sz)w.son=to; 27 } 28 } 29 } 30 void dfs1(int x,int tp){ 31 point&w=q[x];w.id=++sum;mst[sum+mx][0]=mst[sum+mx][1]=w.wi;w.top=tp; 32 if(w.son)dfs1(w.son,tp); 33 for(int i=first[x];i;i=e[i].ne){ 34 int to=e[i].to; 35 if(to!=w.fa&&to!=w.son)dfs1(to,to); 36 } 37 } 38 void up(int x){ 39 mst[x][1]=max1(mst[x<<1][1],mst[x*2+1][1]);mst[x][0]=mst[x<<1][0]+mst[x*2+1][0]; 40 } 41 void build(){for(int l=(mx+1)>>1,r=(mx+n)>>1;l;l>>=1,r>>=1)for(int i=l;i<=r;i++)up(i);} 42 int Sum(int x,int y){ 43 int l,r,ans=0; 44 for(l=x+mx-1,r=y+mx+1;l<r-1;l>>=1,r>>=1){ 45 if(~l&1)ans+=mst[l+1][0]; 46 if(r&1)ans+=mst[r-1][0]; 47 } 48 return ans; 49 } 50 int get_sum(int x,int y){ 51 int ans=0; 52 int a=q[x].top,b=q[y].top; 53 while(a!=b){ 54 if(q[b].dep>q[a].dep)std::swap(a,b),std::swap(x,y); 55 ans+=Sum(q[a].id,q[x].id),x=q[a].fa,a=q[x].top; 56 } 57 if(q[x].dep>q[y].dep)std::swap(x,y); 58 ans+=Sum(q[x].id,q[y].id); 59 return ans; 60 } 61 int Max(int x,int y){ 62 int l,r,ans=-30000; 63 for(l=x+mx-1,r=y+mx+1;l<r-1;l>>=1,r>>=1){ 64 if(~l&1)ans=max1(ans,mst[l+1][1]); 65 if(r&1)ans=max1(ans,mst[r-1][1]); 66 } 67 return ans; 68 } 69 int get_max(int x,int y){ 70 int ans=-30000; 71 int a=q[x].top,b=q[y].top; 72 while(a!=b){ 73 if(q[b].dep>q[a].dep)std::swap(a,b),std::swap(x,y); 74 ans=max1(ans,Max(q[a].id,q[x].id)),x=q[a].fa,a=q[x].top; 75 } 76 if(q[x].dep>q[y].dep)std::swap(x,y); 77 ans=max1(ans,Max(q[x].id,q[y].id)); 78 return ans; 79 } 80 void change(int x,int t){ 81 mst[mx+x][0]=mst[mx+x][1]=t; 82 for(x=x+mx>>1;x;x>>=1)up(x); 83 } 84 int main(){ 85 n=read(); 86 for(int i=1,a,b;i<n;i++)a=read(),b=read(),ins(a,b),ins(b,a); 87 for(int i=1,a;i<=n;i++)a=read(),ai[i]=a; 88 int p=0;for(;(1<<p)<n+10;p++);mx=1<<p; 89 dfs(1,0);dfs1(1,1);build(); 90 int qq=read(); 91 while(qq--){ 92 char ch[8]; 93 scanf("%s",ch);int u=read(),v=read(); 94 if(ch[1]=='H')change(q[u].id,v); 95 else if(ch[1]=='M')printf("%d\n",get_max(u,v)); 96 else printf("%d\n",get_sum(u,v)); 97 } 98 return 0; 99 }