BZOJ 1036: [ZJOI2008]树的统计Count

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 8812  Solved: 3588

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

解题:树链剖分

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int maxn = 30010;
  4 struct arc {
  5     int to,next;
  6     arc(int x = 0,int y = -1) {
  7         to = x;
  8         next = y;
  9     }
 10 } e[maxn<<1];
 11 struct node {
 12     int lt,rt,sum,maxval;
 13 } tree[maxn<<2];
 14 int head[maxn],fa[maxn],top[maxn],dep[maxn];
 15 int siz[maxn],son[maxn],loc[maxn],clk,tot;
 16 void add(int u,int v) {
 17     e[tot] = arc(v,head[u]);
 18     head[u] = tot++;
 19 }
 20 void FindHeavyEdge(int u,int father,int depth) {
 21     fa[u] = father;
 22     dep[u] = depth;
 23     son[u] = -1;
 24     siz[u] = 1;
 25     for(int i = head[u]; ~i; i = e[i].next) {
 26         if(e[i].to == father) continue;
 27         FindHeavyEdge(e[i].to,u,depth + 1);
 28         siz[u] += siz[e[i].to];
 29         if(son[u] == -1 || siz[e[i].to] > siz[son[u]])
 30             son[u] = e[i].to;
 31     }
 32 }
 33 void ConnectHeavyEdge(int u,int ancestor) {
 34     loc[u] = clk++;
 35     top[u] = ancestor;
 36     if(son[u] != -1) ConnectHeavyEdge(son[u],ancestor);
 37     for(int i = head[u]; ~i; i = e[i].next) {
 38         if(e[i].to == fa[u] || son[u] == e[i].to) continue;
 39         ConnectHeavyEdge(e[i].to,e[i].to);
 40     }
 41 }
 42 void build(int lt,int rt,int v) {
 43     tree[v].lt = lt;
 44     tree[v].rt = rt;
 45     tree[v].sum = 0;
 46     tree[v].maxval = 0;
 47     if(lt == rt) return;
 48     int mid = (lt + rt)>>1;
 49     build(lt,mid,v<<1);
 50     build(mid + 1,rt,v<<1|1);
 51 }
 52 void update(int pos,int val,int v) {
 53     if(tree[v].lt == tree[v].rt) {
 54         tree[v].maxval = tree[v].sum = val;
 55         return;
 56     }
 57     if(pos <= tree[v<<1].rt) update(pos,val,v<<1);
 58     if(pos >= tree[v<<1|1].lt) update(pos,val,v<<1|1);
 59     tree[v].sum = tree[v<<1].sum + tree[v<<1|1].sum;
 60     tree[v].maxval = max(tree[v<<1].maxval,tree[v<<1|1].maxval);
 61 }
 62 int querySum(int lt,int rt,int v) {
 63     if(lt <= tree[v].lt && rt >= tree[v].rt) return tree[v].sum;
 64     int ret = 0;
 65     if(lt <= tree[v<<1].rt) ret = querySum(lt,rt,v<<1);
 66     if(rt >= tree[v<<1|1].lt) ret += querySum(lt,rt,v<<1|1);
 67     return ret;
 68 }
 69 int queryMax(int lt,int rt,int v) {
 70     if(lt <= tree[v].lt && rt >= tree[v].rt) return tree[v].maxval;
 71     int ret = -0x3f3f3f3f;
 72     if(lt <= tree[v<<1].rt) ret = queryMax(lt,rt,v<<1);
 73     if(rt >= tree[v<<1|1].lt) ret = max(ret,queryMax(lt,rt,v<<1|1));
 74     return ret;
 75 }
 76 int sum(int a,int b) {
 77     return a + b;
 78 }
 79 int mymax(int a,int b) {
 80     return max(a,b);
 81 }
 82 int CAO(int u,int v,int (*f)(int,int,int),int (*g)(int,int),int ret = 0) {
 83     while(top[u] != top[v]) {
 84         if(dep[top[u]] < dep[top[v]]) swap(u,v);
 85         ret = g(ret,f(loc[top[u]],loc[u],1));
 86         u = fa[top[u]];
 87     }
 88     if(dep[u] > dep[v]) swap(u,v);
 89     ret = g(ret,f(loc[u],loc[v],1));
 90     return ret;
 91 }
 92 int main() {
 93     int n,m,u,v;
 94     while(~scanf("%d",&n)) {
 95         memset(head,-1,sizeof head);
 96         tot = clk = 0;
 97         for(int i = 1; i < n; ++i) {
 98             scanf("%d%d",&u,&v);
 99             add(u,v);
100             add(v,u);
101         }
102         FindHeavyEdge(1,0,0);
103         ConnectHeavyEdge(1,1);
104         build(0,clk-1,1);
105         for(int i = 1; i <= n; ++i){
106             scanf("%d",&u);
107             update(loc[i],u,1);
108         }
109         scanf("%d",&m);
110         char op[20];
111         while(m--){
112             scanf("%s",op);
113             if(op[1] == 'S'){
114                 scanf("%d%d",&u,&v);
115                 printf("%d\n",CAO(u,v,querySum,sum,0));
116             }else if(op[1] == 'H'){
117                 scanf("%d%d",&u,&v);
118                 update(loc[u],v,1);
119             }else if(op[1] == 'M'){
120                 scanf("%d%d",&u,&v);
121                 printf("%d\n",CAO(u,v,queryMax,mymax,-0x3f3f3f3f));
122             }
123         }
124     }
125     return 0;
126 }
127 /*
128 4
129 1 2
130 2 3
131 4 1
132 4 2 1 3
133 12
134 QMAX 3 4
135 QMAX 3 3
136 QMAX 3 2
137 QMAX 2 3
138 QSUM 3 4
139 QSUM 2 1
140 CHANGE 1 5
141 QMAX 3 4
142 CHANGE 3 6
143 QMAX 3 4
144 QMAX 2 4
145 QSUM 3 4
146 */
View Code

 

posted @ 2015-09-29 09:18  狂徒归来  阅读(208)  评论(0编辑  收藏  举报