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
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
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 }
高考结束,重新回归。