树链剖分+线段树 BZOJ 1036 [ZJOI2008]树的统计Count
2016-05-20 13:48
369 查看
题目链接
题意: I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
分析:树链剖分第一题,把树拆成一条条链,有重链和轻链,每个点有转换后的新的位置,同一条链是线性的区间,这样可以用线段树进行操作。第一个是单点更新,第二个先求LCA,然后把u和v移动到lca所在的链,转移一次都是转移链,区间询问最大值和总和,第三种类似。
题意: I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
分析:树链剖分第一题,把树拆成一条条链,有重链和轻链,每个点有转换后的新的位置,同一条链是线性的区间,这样可以用线段树进行操作。第一个是单点更新,第二个先求LCA,然后把u和v移动到lca所在的链,转移一次都是转移链,区间询问最大值和总和,第三种类似。
#include <bits/stdc++.h> const int N = 3e4 + 5; const int D = 20; const int INF = 0x7fffffff; struct Edge { int v, nex; }edge[N<<1]; int head ; int a ; int sz , dep , belong , pos ; int rt [D]; int n, tote, loc; void add_edge(int u, int v) { edge[tote].v = v; edge[tote].nex = head[u]; head[u] = tote++; } void init_edge() { memset (head, -1, sizeof (head)); tote = 0; } void DFS1(int u, int fa) { sz[u] = 1; dep[u] = dep[fa] + 1; rt[u][0] = fa; for (int i=head[u]; ~i; i=edge[i].nex) { int v = edge[i].v; if (v == fa) { continue; } DFS1 (v, u); sz[u] += sz[v]; } } void DFS2(int u, int fa, int chain) { int k = 0; pos[u] = ++loc; belong[u] = chain; for (int i=head[u]; ~i; i=edge[i].nex) { int v = edge[i].v; if (v == fa) { continue; } if (sz[v] > sz[k]) { k = v; } } if (k == 0) { return ; } DFS2 (k, u, chain); for (int i=head[u]; ~i; i=edge[i].nex) { int v = edge[i].v; if (v == fa || v == k) { continue; } DFS2 (v, u, v); } } void init_LCA() { for (int j=1; j<D; ++j) { for (int i=1; i<=n; ++i) { rt[i][j] = rt[i][j-1] == 0 ? 0 : rt[rt[i][j-1]][j-1]; } } } int LCA(int u, int v) { if (dep[u] < dep[v]) { std::swap (u, v); } for (int i=0; i<D; ++i) { if ((dep[u] - dep[v]) >> i & 1) { u = rt[u][i]; } } if (u == v) { return u; } for (int i=D-1; i>=0; --i) { if (rt[u][i] != rt[v][i]) { u = rt[u][i]; v = rt[v][i]; } } return rt[u][0]; } int mx[N<<2], sum[N<<2]; #define lson l, mid, o << 1 #define rson mid + 1, r, o << 1 | 1 void push_up(int o) { mx[o] = std::max (mx[o<<1], mx[o<<1|1]); sum[o] = sum[o<<1] + sum[o<<1|1]; } void updata(int p, int v, int l, int r, int o) { if (l == r) { mx[o] = sum[o] = v; return ; } int mid = l + r >> 1; if (p <= mid) { updata (p, v, lson); } else { updata (p, v, rson); } push_up (o); } int query_max(int ql, int qr, int l, int r, int o) { if (ql <= l && r <= qr) { return mx[o]; } int mid = l + r >> 1, ret = -INF; if (ql <= mid) { ret = std::max (ret, query_max (ql, qr, lson)); } if (qr > mid) { ret = std::max (ret, query_max (ql, qr, rson)); } return ret; } int query_sum(int ql, int qr, int l, int r, int o) { if (ql <= l && r <= qr) { return sum[o]; } int mid = l + r >> 1, ret = 0; if (ql <= mid) { ret += query_sum (ql, qr, lson); } if (qr > mid) { ret += query_sum (ql, qr, rson); } return ret; } int get_sum(int u, int lca) { int ret = 0; while (belong[u] != belong[lca]) { ret += query_sum (pos[belong[u]], pos[u], 1, n, 1); u = rt[belong[u]][0]; } ret += query_sum (pos[lca], pos[u], 1, n, 1); return ret; } int get_max(int u, int lca) { int ret = -INF; while (belong[u] != belong[lca]) { ret = std::max (ret, query_max (pos[belong[u]], pos[u], 1, n, 1)); u = rt[belong[u]][0]; } ret = std::max (ret, query_max (pos[lca], pos[u], 1, n, 1)); return ret; } void prepare() { sz[0] = 0; dep[0] = 0; DFS1 (1, 0); loc = 0; DFS2 (1, 0, 1); init_LCA (); for (int i=1; i<=n; ++i) { updata (pos[i], a[i], 1, n, 1); } } int main() { scanf ("%d", &n); init_edge (); for (int i=1; i<n; ++i) { int u, v; scanf ("%d%d", &u, &v); add_edge (u, v); add_edge (v, u); } for (int i=1; i<=n; ++i) { scanf ("%d", a+i); } prepare (); int q; scanf ("%d", &q); char ch[6]; int x, y; while (q--) { scanf ("%s%d%d", ch, &x, &y); if (ch[0] == 'C') { a[x] = y; updata (pos[x], a[x], 1, n, 1); } else { int lca = LCA (x, y); if (ch[1] == 'M') { printf ("%d\n", std::max (get_max (x, lca), get_max (y, lca))); } else { printf ("%d\n", get_sum (x, lca) + get_sum (y, lca) - a[lca]); } } } return 0; }
相关文章推荐
- Android:通过意图启动其他程序、Uri、setAction、setData、setDataAndType
- 《Linux4.0设备驱动开发详解》笔记--第十三章:Linux块设备驱动
- 设置字符串中某一字为不同的颜色
- eclipse连不上手机和虚拟机
- AndroidStudio应用调试技巧(下)
- HTML-embed标签详解
- mysql中如何嵌套使用insert和select
- 《Linux4.0设备驱动开发详解》笔记--第十二章:Linux设备驱动的软件架构思想
- 关于线程同步(5种同步方式)
- Android TableHost 控件
- [装载]tar命令
- 专注docker安全:Security Scanning
- Oracle外键级联删除和级联更新
- phpMyAdmin创建mysql用户无法登陆/提示密码错误
- SVN无法提交.a文件的解决办法
- 《Linux4.0设备驱动开发详解》笔记--第十一章:内存与I/O访问
- linux修改ip
- VB编程的必备技巧
- 创建一个catkin工作空间
- html中的空格显示问题