【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

Sample Output

4
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 }
bzoj1036

 

posted @ 2017-09-26 08:03  Child-Single  阅读(181)  评论(0编辑  收藏  举报