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 
时间: 2024-11-10 07:31:25

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

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: [ZJOI2008]树的统计Count (树链剖分模板题)

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

BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]

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

bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板

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

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)

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

BZOJ1036: [ZJOI2008]树的统计Count - 树链剖分 -

1036: [ZJOI2008]树的统计Count 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

【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

[BZOJ1036][ZJOI2008]树的统计Count 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

bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 Input 输入的第一行为一个整数n,表示节点的个数.接下来n – 1行,每行

BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时... 代码如下: 1 //树链剖分 点权修改 修改单节点 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cstdio> 6 using namespa

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