bzoj4538: [Hnoi2016]网络 整体二分 差分 树状数组

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvzelong2014/article/details/85683658

bzoj4538: [Hnoi2016]网络

题目传送门

分析

二分最大值呗。
相当于把所有大于这个值的路径筛出来啦。
链修改,点查询->点修改,子树查询。
就是 u , v + 1 u,v+1 l c a , f a [ l c a ] 1 lca,fa[lca]-1
判断某那个点是否经过当前所有链即可。
整体二分上一下即可。

代码

#include<bits/stdc++.h>
const int N = 1e5 + 10, M = 2e5 + 10;
int ri() {
    char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
    for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int pr[N], to[M], nx[M], in[N], out[N], t[N], fa[N], id[M], ans[M], tot, tp, n, mx, cnt;
int p1[M], tp1, p2[M], tp2;
void add(int u, int v) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp;}
void adds(int u, int v) {add(u, v); add(v, u);}
namespace LCA {
    int bin[21], ps[N], Lg[M], mn[21][M], tot;
    int Be(int u, int v) {return ps[u] < ps[v] ? u : v;}
    void Pre() {
        bin[0] = 1; for(int i = 1;i <= 20; ++i) bin[i] = bin[i - 1] << 1;
        Lg[0] = -1; for(int i = 1;i <= tot; ++i) Lg[i] = Lg[i >> 1] + 1;
        for(int j = 1;bin[j] <= tot; ++j)
            for(int i = 1;i + bin[j] - 1 <= tot; ++i)
                mn[j][i] = Be(mn[j - 1][i], mn[j - 1][i + bin[j - 1]]);
    }
    int Lca(int u, int v) {
        u = ps[u]; v = ps[v];
        if(u > v) std::swap(u, v);
        int t = Lg[v - u + 1];
        return Be(mn[t][u], mn[t][v - bin[t] + 1]);
    }
}
void Dfs(int u, int fa) {
    using namespace LCA;
    in[u] = ++::tot; ::fa[u] = fa;
    mn[0][++LCA::tot] = u; ps[u] = LCA::tot;
    for(int i = pr[u]; i; i = nx[i])
        if(to[i] != fa) {
            Dfs(to[i], u);
            mn[0][++LCA::tot] = u;
        }
    out[u] = ::tot;
}
struct Data {
    int tp, u, v, val;
    void In() {
        tp = ri();
        if(!tp) u = ri(), v = ri(), val = ri(), mx = std::max(mx, val);
        else u = ri();
    }
}ev[M], op[M];
void Add(int x, int w) {
    for(;x <= n; x += x &-x)
        t[x] += w;
}
int Que(int x) {
    int r = 0;
    for(;x; x -= x&-x)
        r += t[x];
    return r;
}
void Ins(int u, int v, int w) {
    cnt += w;
    int c = LCA::Lca(u, v);
    Add(in[u], w); Add(in[v], w);
    Add(in[c], -w); if(fa[c]) Add(in[fa[c]], -w);
}
int Query(int u) {return Que(out[u]) - Que(in[u] - 1);}
void Solve(int L, int R, int st, int ed) {
    if(st > ed) return ;
    if(L == R) {
        for(int i = st;i <= ed; ++i)
            if(ev[id[i]].tp == 2)
                ans[id[i]] = L;
        return ;
    }
    int m = L + R >> 1, tp1 = 0, tp2 = 0;
    for(int i = st;i <= ed; ++i) {
        Data u = ev[id[i]];
        if(!u.tp) {
            if(u.val > m)
                Ins(u.u, u.v, 1), p1[tp1++] = id[i];
            else p2[tp2++] = id[i];
        }
        else if(u.tp == 1) {
            Data v = ev[u.u];
            if(v.val > m)
                Ins(v.u, v.v, -1), p1[tp1++] = id[i];
            else p2[tp2++] = id[i];
        }
        else
            Query(u.u) != cnt ? p1[tp1++] = id[i] : p2[tp2++] = id[i];
    }
    for(int i = 0;i < tp1; ++i) { //restore
        Data u = ev[p1[i]];
        if(!u.tp)
            Ins(u.u, u.v, -1);
        else if(u.tp == 1) {
            Data v = ev[u.u];
            Ins(v.u, v.v, 1);
        }
    }
    for(int i = 0;i < tp2; ++i)
        id[st + i] = p2[i];
    for(int i = 0;i < tp1; ++i)
        id[st + tp2 + i] = p1[i];
    Solve(L, m, st, st + tp2 - 1);
    Solve(m + 1, R, st + tp2, ed);
}
int main() {
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    n = ri(); int m = ri();
    for(int i = 1;i < n; ++i)
        adds(ri(), ri());
    Dfs(1, 0); LCA::Pre();
    for(int i = 1;i <= m; ++i) ev[i].In(), id[i] = i;
    Solve(0, mx, 1, m);
    for(int i = 1;i <= m; ++i)
        if(ev[i].tp == 2)
            printf("%d\n", ans[i] ?: -1);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/85683658
今日推荐