码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 1036 树的统计

时间:2015-02-04 09:17:43      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:

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

 

 树链剖分大裸题。
技术分享
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 using namespace std;
  5 #define maxn 30010
  6 #define root 1
  7 int n,next[2*maxn],side[maxn],toit[2*maxn],key[maxn],tot,son[maxn],father[maxn];
  8 int edge[maxn],pos[maxn],top[maxn],dep[maxn],heavy[maxn],ord[maxn];
  9 bool in[maxn];
 10 struct node
 11 {
 12     int l,r;
 13     int best,sum;
 14     int lc,rc;
 15 }seg[4*maxn];
 16  
 17 inline int big(int a,int b){if (a > b)return a;return b;}
 18 inline void add(int,int);
 19 inline void dfs(int,int);
 20 inline void link(int,int);
 21 inline void build(int,int);
 22 inline void change(int,int);
 23 inline void find_best(int,int);
 24 inline void find_sum(int,int);
 25 inline int seg_sum(int,int,int);
 26 inline int seg_best(int,int,int);
 27  
 28 int main()
 29 {
 30     freopen("1036.in","r",stdin);
 31     freopen("1036.out","w",stdout);
 32     scanf("%d",&n);
 33     int i,a,b;
 34     for (i = 1;i<n;i++)
 35     {
 36         scanf("%d %d",&a,&b);
 37         add(a,b); add(b,a);
 38     }
 39     for (i = 1;i<=n;i++)
 40         scanf("%d",key+i);
 41     tot = 0;
 42     dfs(root,1);
 43     tot = 0;
 44     memset(in,0,sizeof(in));
 45     link(root,root);
 46     tot = 1;
 47     build(1,n);
 48     int T;
 49     scanf("%d\n",&T);
 50     char sign[50];
 51     while (T)
 52     {
 53         T--;
 54         scanf("%s %d %d\n",sign,&a,&b);
 55         if (sign[0] == Q)
 56         {
 57             if (sign[1] == M)
 58                 find_best(a,b);
 59             if (sign[1] == S)
 60                 find_sum(a,b);
 61         }
 62         else
 63             key[a] = b,change(a,1);
 64          
 65     }
 66     return 0;
 67 }
 68  
 69 inline void add(int a,int b)
 70 {
 71     tot++;
 72     toit[tot] = b;
 73     next[tot] = side[a];
 74     side[a] = tot;
 75 }
 76  
 77 inline void dfs(int a,int deep)
 78 {
 79     in[a] = true; dep[a] = deep;
 80     int u = side[a],v;
 81     son[a] = 1;
 82     while (u != 0)
 83     {
 84         v = toit[u];
 85         if (!in[v])
 86         {
 87             father[v] = a;
 88             edge[++tot] = v;
 89             dfs(v,deep+1);
 90             if (son[heavy[a]] < son[v])
 91                 heavy[a] = v;
 92             son[a] += son[v];
 93         }
 94         u = next[u];
 95     }
 96 }
 97  
 98 inline void link(int a,int high)
 99 {
100     top[a] = high;
101     pos[a] = ++tot;
102     ord[tot] = a;
103     in[a] = true;
104     if (heavy[a] != 0)
105         link(heavy[a],high);
106     else return;
107     int u = side[a],v;
108     while (u != 0)
109     {
110         v = toit[u];
111         if (!in[v])
112             link(v,v);
113         u = next[u];
114     }
115 }
116  
117 inline void build(int l,int r)
118 {
119     seg[tot].l = l;
120     seg[tot].r = r;
121     if (l == r)
122     {
123         seg[tot].best = key[ord[l]];
124         seg[tot].sum = key[ord[l]];
125         return;
126     }
127     int mid = ((l+r)>>1);
128     int k = tot;
129     seg[k].lc = ++tot;
130     build(l,mid);
131     seg[k].rc = ++tot;
132     build(mid+1,r);
133     seg[k].best = big(seg[seg[k].lc].best,seg[seg[k].rc].best);
134     seg[k].sum = seg[seg[k].lc].sum+seg[seg[k].rc].sum;
135 }
136  
137 inline void change(int a,int now)
138 {
139     if (seg[now].l == seg[now].r)
140     {
141         seg[now].best = key[a];
142         seg[now].sum = key[a];
143         return;
144     }
145     if (seg[seg[now].lc].l<=pos[a]&&seg[seg[now].lc].r>=pos[a])
146         change(a,seg[now].lc);
147     else change(a,seg[now].rc);
148     seg[now].best = big(seg[seg[now].lc].best,seg[seg[now].rc].best);
149     seg[now].sum = seg[seg[now].lc].sum + seg[seg[now].rc].sum;
150 }
151  
152 inline void find_sum(int a,int b)
153 {
154     int sum = 0;
155     while (top[a] != top[b])
156     {
157         if (dep[top[a]]  >= dep[top[b]])
158         {
159             sum += seg_sum(pos[top[a]],pos[a],1);
160             a = father[top[a]];
161         }       
162         else
163         {
164             sum += seg_sum(pos[top[b]],pos[b],1);
165             b = father[top[b]];
166         }
167     }
168     if (pos[a] <= pos[b])
169         sum += seg_sum(pos[a],pos[b],1);
170     else
171         sum += seg_sum(pos[b],pos[a],1);
172     printf("%d\n",sum);
173 }
174  
175 inline void find_best(int a,int b)
176 {
177     int best = -10000000;
178     while (top[a] != top[b])
179     {
180         if (dep[top[a]]  >= dep[top[b]])
181         {
182             best = big(best,seg_best(pos[top[a]],pos[a],1));
183             a = father[top[a]]; 
184         }       
185         else
186         {
187             best = big(best,seg_best(pos[top[b]],pos[b],1));
188             b = father[top[b]];
189         }
190     }
191     if (pos[a] <= pos[b])
192         best = big(best,seg_best(pos[a],pos[b],1));
193     else
194         best = big(best,seg_best(pos[b],pos[a],1));
195     printf("%d\n",best);
196 }
197  
198 inline int seg_best(int l,int r,int now)
199 {
200     if (seg[now].l >=l && seg[now].r <=r)
201         return seg[now].best;
202     int ret =-10000000;
203     int t;
204     t = seg[now].lc;
205     if (seg[t].l<=l&&seg[t].r>=l)
206         ret = big(ret,seg_best(l,r,t));
207     else if (seg[t].l>=l&&seg[t].l<=r)
208         ret = big(ret,seg_best(l,r,t));
209     else if (seg[t].r>=l&&seg[t].r<=r)
210         ret = big(ret,seg_best(l,r,t));
211     t = seg[now].rc;
212     if (seg[t].l<=l&&seg[t].r>=l)
213         ret = big(ret,seg_best(l,r,t));
214     else if (seg[t].l>=l&&seg[t].l<=r)
215         ret = big(ret,seg_best(l,r,t));
216     else if (seg[t].r>=l&&seg[t].r<=r)
217         ret = big(ret,seg_best(l,r,t));
218     return ret;
219 }
220  
221 inline int seg_sum(int l,int r,int now)
222 {
223     if (seg[now].l >=l && seg[now].r <=r)
224         return seg[now].sum;
225     int ret = 0;
226     int t;
227     t = seg[now].lc;
228     if (seg[t].l<=l&&seg[t].r>=l)
229         ret += seg_sum(l,r,t);
230     else if (seg[t].l>=l&&seg[t].l<=r)
231         ret += seg_sum(l,r,t);
232     else if (seg[t].r>=l&&seg[t].r<=r)
233         ret += seg_sum(l,r,t);
234     t = seg[now].rc;
235     if (seg[t].l<=l&&seg[t].r>=l)
236         ret += seg_sum(l,r,t);
237     else if (seg[t].l>=l&&seg[t].l<=r)
238         ret += seg_sum(l,r,t);
239     else if (seg[t].r>=l&&seg[t].r<=r)
240         ret += seg_sum(l,r,t);
241     return ret;
242 }
View Code

 

BZOJ 1036 树的统计

标签:

原文地址:http://www.cnblogs.com/mmlz/p/4271497.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!