bzoj4538: [HNOI2016]网络
2016-09-19 21:46
405 查看
题目链接
维护一颗树。在每个时刻,有以下三个操作。
(u,v,w): 向从u至v的路径上添加一个重要度为w的任务。
(t): 取消t时刻添加的任务。
(x) 查询所有未覆盖x节点的任务中重要度的最大值。
这道题有诸多做法,然而我直接当做树链剖分练习题来做了。
对于这样的三个操作,我们可以考虑用树剖来维护。查询不覆盖某节点的任务难以直接用线段树实现,我们可以反其道而行之,将操作1中的覆盖区间取补集,查询时输出x点被1操作覆盖的任务的最大值。这样的操作与原操作等价。考虑到一个节点会被多个任务覆盖或取消覆盖,可以向线段树的每个节点套一个大根堆,查询时对所有覆盖该点的线段的堆顶元素取max。三个树套在一起,时间复杂度为O(Nlog3N),空间复杂度为O(Nlog2N)
这题还可以用kdtree,点分治,二分+树链交等各种优雅的做法秒杀,然而我一个都不会。
维护一颗树。在每个时刻,有以下三个操作。
(u,v,w): 向从u至v的路径上添加一个重要度为w的任务。
(t): 取消t时刻添加的任务。
(x) 查询所有未覆盖x节点的任务中重要度的最大值。
这道题有诸多做法,然而我直接当做树链剖分练习题来做了。
对于这样的三个操作,我们可以考虑用树剖来维护。查询不覆盖某节点的任务难以直接用线段树实现,我们可以反其道而行之,将操作1中的覆盖区间取补集,查询时输出x点被1操作覆盖的任务的最大值。这样的操作与原操作等价。考虑到一个节点会被多个任务覆盖或取消覆盖,可以向线段树的每个节点套一个大根堆,查询时对所有覆盖该点的线段的堆顶元素取max。三个树套在一起,时间复杂度为O(Nlog3N),空间复杂度为O(Nlog2N)
这题还可以用kdtree,点分治,二分+树链交等各种优雅的做法秒杀,然而我一个都不会。
#include <queue> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; struct event { int val, id; inline bool operator < (const event &rhs) const { return val < rhs.val; } }tmpe; typedef priority_queue<event> heap; const int N = 100010; int n, m; vector<int> E ; int size , dep , fa , son , top , seg , segCnt; void dfs1(int u, int f) { size[u] = 1; dep[u] = dep[fa[u] = f] + 1; for (int i = 0; i < E[u].size(); i++) { int &v = E[u][i]; if (v == f) continue; dfs1(v, u); size[u] += size[v]; if (size[v] > size[son[u]]) son[u] = v; } } void dfs2(int u, int tp) { top[u] = tp; seg[u] = ++segCnt; if (! son[u]) return; dfs2(son[u], tp); for (int i = 0; i < E[u].size(); i++) { int &v = E[u][i]; if (v == fa[u] || v == son[u]) continue; dfs2(v, v); } } inline void initTree() { dfs1(1, 0); dfs2(1, 1); } bool disable[N<<1]; heap hp[N<<1]; #define g(l, r) (l + r | l != r) #define o g(l, r) #define ls g(l, mid) #define rs g(mid + 1, r) int gl, gr, gans; #define cg(l, r) gl = l; \ gr = r #define H hp[o] void ins(int l, int r) { if (gl > gr) return; if (gl <= l && r <= gr) { H.push(tmpe); return; } int mid = l + r >> 1; if (gl <= mid) ins(l, mid); if (mid + 1 <= gr) ins(mid + 1, r); } void query(int l, int r) { while (! H.empty() && disable[H.top().id]) H.pop(); if (! H.empty()) gans = max(gans, H.top().val); if (l == r) return; int mid = l + r >> 1; if (gl <= mid) query(l, mid); else query(mid + 1, r); } event cf[110<<1]; inline void Insert(int u, int v) { int ecnt = 0; int f1 = top[u], f2 = top[v]; while (f1 != f2) { if (dep[f1] < dep[f2]) { swap(f1, f2); swap(u, v); } cf[++ecnt] = (event){seg[f1], 1}; cf[++ecnt] = (event){seg[u] + 1, -1}; u = fa[f1], f1 = top[u]; } if (dep[u] < dep[v]) swap(u, v); cf[++ecnt] = (event){seg[v], 1}; cf[++ecnt] = (event){seg[u] + 1, -1}; //O(logNlog(logN))差分求补集 sort(cf + 1, cf + 1 + ecnt); int sum = 0, left = 1; for (int i = 1; i <= ecnt; i++) { if (sum == 0) { cg(left, cf[i].val - 1); ins(1, n); sum += cf[i].id; } else { sum += cf[i].id; if (sum == 0) left = cf[i].val; } } cg(left, n); ins(1, n); } inline void Query(int u) { gans = -1; cg(seg[u], seg[u]); query(1, n); printf("%d\n", gans); } inline void work() { for (int id = 1; id <= m; id++) { int type; scanf("%d", &type); if (type == 0) { int a, b, v; scanf("%d%d%d", &a, &b, &v); tmpe = (event){v, id}; Insert(a, b); } if (type == 1) { int t; scanf("%d", &t); disable[t] = true; } if (type == 2) { int x; scanf("%d", &x); Query(x); } } } int main() { cin >> n >> m; for (int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); E[u].push_back(v); E[v].push_back(u); } initTree(); work(); return 0; }
相关文章推荐
- bzoj4538: [Hnoi2016]网络
- bzoj4538: [Hnoi2016]网络
- bzoj4538 [Hnoi2016]网络
- Bzoj4538:[Hnoi2016]网络:整体二分+树状数组
- 【BZOJ4538】[Hnoi2016]网络 整体二分+树状数组
- [bzoj4538][Hnoi2016]网络
- bzoj4538 [Hnoi2016]网络(树链剖分,线段树套堆)
- [bzoj4538][Hnoi2016]网络
- (BZOJ4538)HNOI2016 网络
- BZOJ4538: [Hnoi2016]网络
- bzoj4538 [Hnoi2016]网络
- 【BZOJ4538】【HNOI2016】网络
- BZOJ4538 : [Hnoi2016]网络
- [BZOJ4538][HNOI2016]网络-线段树-树链剖分
- 【bzoj4538】【HNOI2016】【网络】【树链剖分+线段树套堆】
- bzoj4538 [Hnoi2016]网络
- 【BZOJ4538】【HNOI2016】网络
- bzoj4538: [Hnoi2016]网络
- bzoj4538 [Hnoi2016]网络
- 【bzoj4538】[Hnoi2016]网络