BZOJ 1036 树的统计

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 }

时间: 2024-10-07 07:46:05

BZOJ 1036 树的统计的相关文章

BZOJ 1036 树的统计-树链剖分

[ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 12904 Solved: 5191[Submit][Status][Discuss]Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM

BZOJ 1036 树的统计(树链剖分)

PS:树链剖分的很基本的题 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 #define dec(i, a, b) for (int i(a); i >= (b); --i) 7 #define lson i << 1, L, mid 8 #define rson i << 1 | 1,

bzoj 1036 树的统计Count (树链剖分+线段树)

题目大意:给你一棵树,每个点都有点权 有3种操作,修改某节点的权值,求树链上节点的权值的最大值,求树链上节点的权值和 树剖裸题,搜一个树链剖分序,用线段树维护一下即可,总时间 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <queue> 5 #define inf 0x3f3f3f3f 6 #define ll long long 7 #define N

HYSBZ 1036 树的统计Count(树链剖分)

HYSBZ 1036 树的统计Count 题目链接 就树链剖分,线段树维护sum和maxx即可 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 30005; int dep[N], fa[N], son[N], sz[N], top[N], id[N], idx, val[N];

HYSBZ - 1036 树的统计Count 树链剖分 求和+最大值

好水0.0 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #include<string> #define eps 1e-12 #de

BZOJ 1036 树链剖分模板题

BZOJ 1036 题意:一棵树,每个点有权值,三种操作:修改一个点的值:询问一条链上最大值:询问一条链上权值和. tags:模板题 // bzoj 1036 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define FF(i,a,b) for (int i=a;i<=b;i++) #define F(i,b,a)

spoj 375 AND bzoj 1036 树链剖分

树链剖分的入门题目,自己写了下感觉还是挺好写的,不过真的有点长... spoj 375 边有权值: 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int INF = -999999999; 7 const int N = 10001; 8 int head[N]; 9 int sz[N]; 10 int depth[N]; 1

bzoj 1036 树链剖分+线段树 裸题

HYSBZ - 1036 题意:中文题 思路:树链剖分裸题,线段树写得比较搓,(在线段树上修改节点u的时候应该修改u映射到线段树后的节点序号,这里wa了半年,真的是半年) AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector

HYSBZ 1036 树的统计Count 树链剖分 线段树

傻缺模板题,练手速和正确率用.. #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <set> #include <bitset> #include <queue> #include <stack> #include <string> #include <iostream>