COGS-2295 榴莲(整体二分+树状数组+树上差分)
来源:互联网 发布:06年韦德总决赛数据 编辑:程序博客网 时间:2024/04/30 04:21
2295. [HZOI 2015]榴莲
★★☆ 输入文件:Durio_zibethinus_Murr.in
输出文件:Durio_zibethinus_Murr.out
简单对比时间限制:1 s 内存限制:512 MB
【题目描述】
众所周知,榴莲长在树上,同时榴莲很臭
现在给定你一棵榴莲树,树根为1
要求你维护以下操作:
1、 1 u v w 树上长出一个榴莲,臭味度为w,臭味弥漫了树上u到v的简单路径上所有点
2、 2 u w 树上长出一个榴莲,臭味度为w,臭味弥漫了树上u的子树的所有点
3、 3 k 树上k时刻长出的榴莲从树上掉了下来,它所造成的臭味效果消失
4、 4 u k 询问所有弥漫到u节点的榴莲臭味值的第k大
【输入格式】
第一行输入n,m表示节点总数和操作次数
以下n-1行u,v描述两个端点
以下m行,第i行表示第i个时刻的操作如题意所示
n,m<=100000
数据保证第三个操作掉下来的是存在的且尚未掉下来的榴莲
【输出格式】
对于每个询问
若弥漫到u节点的榴莲不足k个,则输出-1
否则输出对应的答案
【样例输入】
10 10
2 1
3 1
4 3
5 4
6 1
7 3
8 3
9 7
10 2
4 1 1
1 3 1 13881
3 2
2 10 12573
2 7 2522
1 10 7 7976
1 7 7 15696
4 2 1
1 3 4 14384
1 10 9 7398
【样例输出】
-1
7976
首先预处理出DFS序和LCA,设in[u]和out[u]是以u为根节点的子树的最小和最大的DFS序
对于修改操作,用树状数组维护贡献:
①链上操作(X,Y):
这个操作等价于
a. 对X到根节点路径上所有点贡献+1
b. 对Y到根节点路径上所有点贡献+1
c. 对LCA(X, Y)到根节点路径上所有点贡献-1
d. 对LCA(X,Y)的父节点 par[LCA(X, Y)]到根节点路径上所有点贡献-1
②子树操作(X):这个操作等价于将DFS序为in[u]~out[u]之间的点贡献+1
我们可以二分答案m,之后扫一遍之前的操作我们只需要知道有多少个权值>=m的操作经过当前点u就可以了,如果k不超过在这个节点的贡献cnt,则放入右区间,否则将k-=cnt并放入左区间。最后判断一下k是否小于或等于0,是的话答案为m,否则为-1(没有k个臭味)
#include<bits/stdc++.h>using namespace std;typedef long long LL;const int MX = 1e5 + 5;const LL inf = 0x3f3f3f3f3f3f3f3f;struct Tree { int n; vector <int> T; void init (int _n) { T.clear(); n = _n; T.resize(n + 1); } void add (int x, int v) { for (int i = x; i <= n; i += i & -i) T[i] += v; } int sum (int x) { if (x > n) x = n; int ret = 0; for (int i = x; i > 0; i -= i & -i) ret += T[i]; return ret; }} bt1, bt2;struct Query { int op, u, v, w, k, id;} que[MX], t1[MX], t2[MX];struct Edge { int v, nxt;} E[MX * 2];int head[MX], tot, ans[MX], h[MX], mark[MX];void add(int u, int v) { E[tot].v = v; E[tot].nxt = head[u]; head[u] = tot++;}//ver:节点编号 deep:深度 first:点编号位置 dir:距离int sz, ver[2 * MX], deep[2 * MX], first[MX], dp[2 * MX][30], vis[MX], dir[MX];int rear, seq[2 * MX], in[MX], out[MX], pre[MX];void init(int n) { for (int i = 0; i <= n; i++) dir[i] = vis[i] = 0; sz = 0;}void dfs(int u, int dep, int fa) { vis[u] = true; ver[++sz] = u; first[u] = sz; deep[sz] = dep; seq[++rear] = u; in[u] = rear; pre[u] = fa; for (int i = head[u]; ~i ; i = E[i].nxt) { if ( vis[E[i].v] ) continue; int v = E[i].v; dir[v] = dir[u] + 1; dfs(v, dep + 1, u); ver[++sz] = u; deep[sz] = dep; } seq[++rear] = u; out[u] = rear;}void ST(int n) { for (int i = 1; i <= n; i++) dp[i][0] = i; for (int j = 1; (1 << j) <= n; j++) { for (int i = 1; i + (1 << j) - 1 <= n; i++) { int a = dp[i][j - 1], b = dp[i + (1 << (j - 1))][j - 1]; dp[i][j] = deep[a] < deep[b] ? a : b; } }}int RMQ(int l, int r) { int k = 0; while ((1 << (k + 1)) <= r - l + 1) k++; int a = dp[l][k], b = dp[r - (1 << k) + 1][k]; //保存的是编号 return deep[a] < deep[b] ? a : b;}int LCA(int u, int v) { int x = first[u], y = first[v]; if (x > y) swap(x, y); int ret = RMQ(x, y); return ver[ret];}void pre_solve(int n) { dir[1] = 1; dfs(1, 1, 0); ST(sz);}inline void update1(int u, int v, int lca, int val) { bt1.add(in[u], val); bt1.add(in[v], val); bt1.add(in[lca], -val); if (pre[lca]) bt1.add(in[pre[lca]], -val);}inline void update2(int u, int val) { bt2.add(in[u], val); bt2.add(out[u], -val);}void work1(int L, int R, int m) { for (int i = L, u, v, lca; i <= R; i++) { if (que[i].op == 1) { if (que[i].w == m) { update1(que[i].u, que[i].v, LCA(que[i].u, que[i].v), 1); mark[que[i].id] = i; } } if (que[i].op == 2) { if (que[i].w == m) { update2(que[i].u, 1); mark[que[i].id] = i; } } if (que[i].op == 3) { if (mark[que[i].k]) { int j = mark[que[i].k]; mark[que[j].id] = 0; if (que[j].op == 1) update1(que[j].u, que[j].v, LCA(que[j].u, que[j].v), -1); else update2(que[j].u, -1); } } if (que[i].op == 4) { u = que[i].u; int sum = bt1.sum(out[u]) - bt1.sum(in[u] - 1) + bt2.sum(in[u]); que[i].k -= sum; } } for (int i = L; i <= R; i++) { if (mark[que[i].id]) { if (que[i].op == 1) update1(que[i].u, que[i].v, LCA(que[i].u, que[i].v), -1); else update2(que[i].u, -1); } mark[que[i].id] = 0; }}void work2(int L, int R, int m, int &p1, int &p2) { p1 = 0, p2 = 0; for (int i = L, u, v, lca; i <= R; i++) { if (que[i].op == 1) { if (que[i].w < m) t1[p1++] = que[i]; else { update1(que[i].u, que[i].v, LCA(que[i].u, que[i].v), 1); t2[p2++] = que[i], mark[que[i].id] = i; } } if (que[i].op == 2) { if (que[i].w < m) t1[p1++] = que[i]; else { update2(que[i].u, 1); t2[p2++] = que[i], mark[que[i].id] = i; } } if (que[i].op == 3) { if (!mark[que[i].k]) t1[p1++] = que[i]; else { int j = mark[que[i].k]; mark[que[i].k] = 0; if (que[j].op == 1) update1(que[j].u, que[j].v, LCA(que[j].u, que[j].v), -1); else update2(que[j].u, -1); t2[p2++] = que[i]; } } if (que[i].op == 4) { u = que[i].u; int sum = bt1.sum(out[u]) - bt1.sum(in[u] - 1) + bt2.sum(in[u]); if (sum < que[i].k) que[i].k -= sum, t1[p1++] = que[i]; else t2[p2++] = que[i]; } } for (int i = 0; i < p1; i++) que[L + i] = t1[i], mark[t1[i].id] = 0; for (int i = 0; i < p2; i++) { if (mark[t2[i].id]) { if (t2[i].op == 1) update1(t2[i].u, t2[i].v, LCA(t2[i].u, t2[i].v), -1); else update2(t2[i].u, -1); } que[L + p1 + i] = t2[i], mark[t2[i].id] = 0; }}void solve(int L, int R, int l, int r) { if (L > R || l > r) return; if (l == r) { work1(L, R, l); for (int i = L; i <= R; i++) { if (que[i].op != 4) continue; if (que[i].k <= 0) ans[que[i].id] = h[l]; else ans[que[i].id] = -1; } return; } int m = (l + r + 1) >> 1, p1, p2; work2(L, R, m, p1, p2); solve(L, L + p1 - 1, l, m - 1); solve(L + p1, R, m, r);}int main() { //freopen("in.txt", "r", stdin); freopen("Durio_zibethinus_Murr.in", "r", stdin); freopen("Durio_zibethinus_Murr.out", "w+", stdout); int n, m; scanf("%d%d", &n, &m); memset(head, -1, sizeof(head)); for (int i = 1, u, v; i < n; i++) scanf("%d%d", &u, &v), add(u, v), add(v, u); pre_solve(n); bt1.init(rear); bt2.init(rear); int mx = 0, cnt = 0; for (int i = 1; i <= m; i++) { scanf("%d", &que[i].op); if (que[i].op == 1) scanf("%d%d%d", &que[i].u, &que[i].v, &que[i].w), h[++cnt] = que[i].w, mx = max(que[i].w, mx); if (que[i].op == 2) scanf("%d%d", &que[i].u, &que[i].w), h[++cnt] = que[i].w, mx = max(que[i].w, mx); if (que[i].op == 3) scanf("%d", &que[i].k); if (que[i].op == 4) scanf("%d%d", &que[i].u, &que[i].k); que[i].id = i; ans[i] = -2; } sort(h + 1, h + cnt + 1); cnt = unique(h + 1, h + cnt + 1) - h - 1; for (int i = 1; i <= m; i++) if (que[i].op == 1 || que[i].op == 2) que[i].w = lower_bound(h + 1, h + cnt + 1, que[i].w) - h; solve(1, m, 0, mx); for (int i = 1; i <= m; i++) if (ans[i] >= -1)printf("%d\n", ans[i]); return 0;}
- COGS-2295 榴莲(整体二分+树状数组+树上差分)
- BZOJ 1103: [POI2007]大都市meg 树上差分 树状数组
- BZOJ1103【POI2007】大都市meg <树上差分+树状数组>
- [BZOJ1103][POI2007]大都市meg(树状数组维护树上差分)
- [BZOJ4326][NOIP2015]运输计划(二分答案+树上差分)
- bzoj 4326 运输计划 (树链剖分 + 树上差分 + 二分)
- Luogu-2680 (二分答案+树上差分)
- JZOJ5394. 【NOIP2017提高A组模拟10.5】Ping 树上差分 树状数组
- BZOJ2738【整体二分】【树状数组】
- LuoguP2680/UOJ150[NOIP2015] 运输计划 解题报告【二分答案+树上操作(LCA)+树上差分】
- luogu3368 树状数组+差分
- BZOJ 4326 NOIP 2015 DAY2 T3 浅谈二分及树上差分数组DFS动态统计
- 树状网络攻击(LCA和树上差分的应用)
- [BZOJ2674]Attack(整体二分+树状数组套线段树)
- bzoj 2527: [Poi2011]Meteors (树状数组+整体二分)
- bzoj 2738: 矩阵乘法 (整体二分+二维树状数组)
- 【BZOJ2738】矩阵乘法(整体二分+二位树状数组)
- [BZOJ2674]Attack(整体二分+树状数组套线段树)
- 复习总结04:HBase(含重要原理图!吐血整理HBase存储机制!)
- 下一个排列-LintCode
- Ubuntu下安装及配置Postgresql
- poj3728并查集+LCA
- 释放线上日志文件空间
- COGS-2295 榴莲(整体二分+树状数组+树上差分)
- 在浏览网页时,网页里面的文档不能正常显示
- 定义函数的方法和区别
- 第11讲项目2-分离整数和小数部分
- platform总线按键驱动分析
- 【面试】常见的前端面试题(1)
- BZOJ 1631: [Usaco2007 Feb]Cow Party
- @property (nonatomic, getter=isLoading) BOOL loading;getter=isLoading的含义
- unity调用摄像头和闪光灯