bzoj4538: [HNOI2016]网络

来源:互联网 发布:淘宝运费险是自动退吗 编辑:程序博客网 时间:2024/06/04 19:32

题目链接

维护一颗树。在每个时刻,有以下三个操作。

  1. (u,v,w): 向uv的路径上添加一个重要度为w的任务。
  2. (t): 取消t时刻添加的任务。
  3. (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[N];int size[N], dep[N], fa[N], son[N], top[N], seg[N], 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;}
1 0