[BZOJ] 1036: [ZJOI2008]树的统计Count

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 18843  Solved: 7689
[Submit][Status][Discuss]

Description

  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作:

I. CHANGE u t : 把结点u的权值改为t 

II. QMAX u v: 询问从点u到v的路径上的节点的最大权值

III. 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

HINT

 

Source

 

Analysis

树链剖分裸题!

在此推荐 ACdreamer的树链剖分原理 !

=w=

树链剖分可以用百度到的一张图解释

那么显然树链剖分还有第三个性质(主要是帮助理解的)

    “ 每一个点都在重链上 ”

(其实有点废话,不过我一直对树剖有些相关误解)

那么具体实现的时候,我们通过魔改他们的DFS序(优先遍历同一条重链上的子节点),然后把新版DFS序塞进线段树

这样重链就都头尾相接了 =w=

这里不对树剖做出详细的讲解(反正前人之述备矣而且还有ACdreamer大大的解释)

只是一些零散的注释

如果明明敲起来很顺又不觉得有什么问题

看看你的函数有没有返回答案= =

(本蒟蒻忘记返回值结果挂了)

关于如何跳链 :

操作的时候优先操作重链链头深度更深的

也就是不停地操作深链然后一步步跳到同一条链上

 

Code

  1 #include<cstdio>
  2 #include<iostream>
  3 #define maxn 1000000
  4 #define lc (rt<<1)
  5 #define rc (rt<<1|1)
  6 #define mid ((L+R)/2)
  7 using namespace std;
  8 
  9 const int inf = 1e9;
 10 
 11 int arr[maxn],siz[maxn],fa[maxn],depth[maxn],son[maxn],top[maxn],tid[maxn],TIM;
 12 int back[maxn],n,q;
 13 
 14 struct edge{
 15     int from,v;
 16 }e[maxn];
 17 int tot,first[maxn];
 18 void insert(int u,int v){ tot++; e[tot].from = first[u]; e[tot].v = v; first[u] = tot; }
 19 
 20 struct node{
 21     int sum,maxx,lazy;
 22 }Tree[maxn];
 23 
 24 void maintain(int rt){ 
 25     Tree[rt].sum = Tree[lc].sum+Tree[rc].sum; 
 26     Tree[rt].maxx = max(Tree[lc].maxx,Tree[rc].maxx);
 27 }
 28 
 29 void pushdown(int rt,int L,int R){
 30     if(Tree[rt].lazy == -inf) return;
 31     Tree[lc].lazy = Tree[rt].lazy;
 32     Tree[rc].lazy = Tree[rt].lazy;
 33     Tree[rt].lazy = -inf;
 34     Tree[lc].sum = Tree[rt].lazy*(mid-L+1);
 35     Tree[lc].maxx = Tree[rt].lazy;
 36     Tree[rc].sum = Tree[rt].lazy*(R-mid);
 37     Tree[rc].maxx = Tree[rt].lazy;
 38 }
 39 
 40 void build(int rt,int L,int R){
 41     Tree[rt].lazy = -inf;
 42     if(L == R){
 43         Tree[rt].sum = arr[L];
 44         Tree[rt].maxx = arr[L];
 45     }else{
 46         build(lc,L,mid);
 47         build(rc,mid+1,R);
 48         
 49         maintain(rt);
 50     }
 51 }
 52 
 53 void modify(int rt,int L,int R,int qL,int qR,int val){
 54     pushdown(rt,L,R);
 55     if(qL <= L && R <= qR){
 56         Tree[rt].lazy = val;
 57         Tree[rt].sum = val*(R-L+1);
 58         Tree[rt].maxx = val;
 59     }else{
 60         if(qL <= mid) modify(lc,L,mid,qL,qR,val);
 61         if(qR > mid) modify(rc,mid+1,R,qL,qR,val);
 62         
 63         maintain(rt);
 64     }
 65 }
 66 
 67 int max_query(int rt,int L,int R,int qL,int qR){
 68     pushdown(rt,L,R);
 69     if(qL <= L && R <= qR) return Tree[rt].maxx;
 70     else{
 71         int ans = -inf;
 72         if(qL <= mid) ans = max(ans,max_query(lc,L,mid,qL,qR));
 73         if(qR > mid) ans = max(ans,max_query(rc,mid+1,R,qL,qR));
 74         return ans;
 75     }
 76 }
 77 
 78 int sum_query(int rt,int L,int R,int qL,int qR){
 79     pushdown(rt,L,R);
 80     if(qL <= L && R <= qR) return Tree[rt].sum;
 81     else{
 82         int ans = 0;
 83         if(qL <= mid) ans += sum_query(lc,L,mid,qL,qR);
 84         if(qR > mid) ans += sum_query(rc,mid+1,R,qL,qR);
 85         return ans;
 86     }
 87 }
 88 
 89 void dfs(int now){
 90     siz[now] = 1;
 91     for(int i = first[now];i;i = e[i].from){
 92         int v = e[i].v;
 93         if(v != fa[now]){
 94             fa[v] = now;
 95             depth[v] = depth[now]+1;
 96             dfs(v);
 97             siz[now] += siz[v];
 98             if(!son[now] || siz[v] > siz[son[now]])
 99                 son[now] = v;
100         }
101     }
102 }
103 
104 void dfs2(int now,int upper){
105     top[now] = upper;
106     tid[now] = ++TIM;
107     back[TIM] = now;
108     if(!son[now]) return;
109     dfs2(son[now],upper);
110     for(int i = first[now];i;i = e[i].from){
111         int v = e[i].v;
112         if(v != fa[now] && v != son[now])
113             dfs2(v,v);
114     }
115 }
116 
117 void CHANGE(int u,int val){
118     modify(1,1,n,tid[u],tid[u],val);
119 }
120 
121 int QMAX(int u,int v){
122     if(depth[top[u]] > depth[top[v]]) swap(u,v);
123     int ans = -inf;
124     while(top[u] != top[v]){
125         ans = max(max_query(1,1,n,tid[top[v]],tid[v]),ans);
126         v = fa[top[v]];
127         if(depth[top[u]] > depth[top[v]]) swap(u,v);
128     }if(depth[u] > depth[v]) swap(u,v);
129     ans = max(ans,max_query(1,1,n,tid[u],tid[v]));
130     return ans;
131 }
132 
133 int QSUM(int u,int v){
134     if(depth[top[u]] > depth[top[v]]) swap(u,v);
135     int ans = 0;
136     while(top[u] != top[v]){
137         ans += sum_query(1,1,n,tid[top[v]],tid[v]);
138         v = fa[top[v]];
139         if(depth[top[u]] > depth[top[v]]) swap(u,v);
140     }if(depth[u] > depth[v]) swap(u,v);
141     ans += sum_query(1,1,n,tid[u],tid[v]);
142     return ans;
143 }
144 
145 int main(){
146     scanf("%d",&n);
147     for(int i = 1;i < n;i++){
148         int x,y; scanf("%d%d",&x,&y);
149         insert(x,y); insert(y,x);
150     }depth[1] = 1; dfs(1); dfs2(1,1);
151     
152     for(int i = 1;i <= n;i++)
153         scanf("%d",&arr[tid[i]]);
154     build(1,1,n);
155         
156     scanf("%d",&q);
157     while(q--){
158         char str[10];
159         scanf("%s",str); int a,b;
160         switch(str[1]){
161             case 'M': //QMAX
162                 scanf("%d%d",&a,&b);
163                 printf("%d\n",QMAX(a,b));
164                 break;
165             case 'S': //QSUM
166                 scanf("%d%d",&a,&b);
167                 printf("%d\n",QSUM(a,b));
168                 break;
169             case 'H': //CHANGE
170                 scanf("%d%d",&a,&b);
171                 CHANGE(a,b);
172                 break;
173         }
174     }
175     
176     return 0;
177 }
=w=美滋滋

 

posted @ 2017-10-09 21:29  Leviaton  阅读(224)  评论(0编辑  收藏  举报