首页 > 代码库 > bzoj 1036: [ZJOI2008]树的统计Count (树链剖分)

bzoj 1036: [ZJOI2008]树的统计Count (树链剖分)

ps:这道题过的人真多啊

一道树剖的模板题

(好像还可以用lct做, 然而我并不会

代码如下

  1 /**************************************************************
  2     Problem: 1036
  3     User: cminus
  4     Language: C++
  5     Result: Accepted
  6     Time:2380 ms
  7     Memory:4052 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #include <vector>
 12 #include <algorithm>
 13 #include <cstring>
 14 using namespace std;
 15 const int N = 30100;
 16 #define ls (o << 1)
 17 #define rs (ls + 1)
 18   
 19 int n, w[N];
 20 int fa[N], size[N], hs[N], dep[N], top[N], pos[N], tot;
 21 int maxn[N*4], sum[N*4], L, R;
 22 vector < int > edge[N]; 
 23   
 24 inline void dfs1(int u, int d, int f){
 25     dep[u] = d; fa[u] = f; size[u] = 1; hs[u] = -1;
 26     int tmp = 0;
 27     for (int i = 0; i < edge[u].size(); i++){
 28         int &v = edge[u][i];
 29         if (v == f)  continue;
 30         dfs1(v, d + 1, u);
 31         if (size[v] > tmp)
 32             tmp = size[v], hs[u] = v;
 33         size[u] += size[v];
 34     }
 35 }
 36   
 37 inline void dfs2(int u, int t){
 38     top[u] = t, pos[u] = ++tot;
 39     if (hs[u] == -1)    return ;
 40     dfs2(hs[u], t);
 41     for (int i = 0; i < edge[u].size(); i++){
 42         int &v = edge[u][i];
 43         if (v != hs[u] && v != fa[u])
 44             dfs2(v, v);
 45     }
 46 }
 47   
 48 inline int getSum(int o, int l, int r){
 49     if (L <= l && r <= R) return sum[o];
 50     int mid = (l + r) >> 1, ans = 0;
 51     if (L <= mid)    ans += getSum(ls, l, mid);
 52     if (R > mid)     ans += getSum(rs, mid + 1, r);
 53     return ans;
 54 }
 55   
 56 inline int getMax(int o, int l, int r){
 57     if (L <= l && r <= R) return maxn[o];
 58     int mid = l + r >> 1, ans = -0x3f3f3f3f;
 59     if (L <= mid)    ans = max(ans, getMax(ls, l, mid));
 60     if (R > mid) ans = max(ans, getMax(rs, mid + 1, r));
 61     return ans;
 62 }
 63   
 64 inline int getMax(int l, int r){
 65     L = l, R = r;
 66     return  getMax(1, 1, tot);
 67 }
 68   
 69 inline int getSum(int l, int r){
 70     L = l, R = r;
 71     return getSum(1, 1, tot);
 72 }
 73   
 74 inline void queryMax(int u, int v){
 75     int f1 = top[u], f2 = top[v], ans = -0x3f3f3f3f;
 76     while(f1 != f2){
 77         if (dep[f1] < dep[f2])
 78             swap(u, v), swap(f1, f2);
 79         ans = max(ans, getMax(pos[f1], pos[u]));
 80         u = fa[f1]; f1 = top[u];
 81     }
 82     if (dep[u] > dep[v]) swap(u, v);
 83     printf("%d\n", max(ans, getMax(pos[u], pos[v])));
 84 }
 85   
 86 inline void querySum(int u, int v){
 87     int f1 = top[u], f2 = top[v], ans = 0;
 88     while(f1 != f2){
 89         if (dep[f1] < dep[f2])
 90             swap(u, v), swap(f1, f2);
 91         ans += getSum(pos[f1], pos[u]);
 92         u = fa[f1]; f1 = top[u]; 
 93     }
 94     if (dep[u] > dep[v]) swap(u, v);
 95     printf("%d\n", ans + getSum(pos[u], pos[v]));
 96 }
 97   
 98 inline void modify(int o, int l, int r, int u, int a){
 99     if(l == r){
100         sum[o] = maxn[o] = a;
101         return ;
102     }
103     int mid = l + r >> 1;
104     if (u <= mid)    modify(ls, l, mid, u, a);
105     else    modify(rs, mid + 1, r, u, a);
106     sum[o] = sum[ls] + sum[rs];
107     maxn[o] = max(maxn[ls], maxn[rs]);
108 }
109   
110 int main(){
111     scanf("%d", &n);
112     for (int i = 1; i < n; i++){
113         int x, y; scanf("%d %d", &x, &y);
114         edge[x].push_back(y);
115         edge[y].push_back(x);
116     }
117     for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
118     dfs1(1, 1, -1); dfs2(1, 1);
119     for (int i = 1; i <= n; i++)
120         modify(1, 1, tot, pos[i], w[i]);
121     int q;  scanf("%d", &q);
122     char str[10]; int x, y;
123     while(q--){
124         scanf("%s%d%d", str, &x, &y);
125         if (!strcmp(str, "QMAX"))   queryMax(x, y);
126         else if (*str == C)   modify(1, 1, tot, pos[x], y);
127         else querySum(x, y);
128     }
129     return 0;
130 } 
131 

 

bzoj 1036: [ZJOI2008]树的统计Count (树链剖分)