zoukankan      html  css  js  c++  java
  • Luogu4172 WC2006水管局长

    首先声明,这份代码空间复杂度 (O(n^2)),瓶颈在给边打标记

    由于博主太菜,懒得再改成低复杂度的打标记了,所以(BZOJ)的数据过不去

    Description

    link

    给一张图,会有删边操作,求当前图路径((x,y)) 的最大边权

    (n leq 10^3 ,m le 10^5)

    (BZOJ)版:(nle 10^5,mle10^6)

    Solution

    这个题把询问离线下来,然后逆序加边,用 (LCT) 维护边权

    这里有一个点边转化:

    把每一个边拆成点,对端点连两条边(边权就是(e[i].dis)),这样就可以维护点权了,在(link)(cut)操作中有点点不同

    如下:

    cut(e[tmp - n].from, tmp);
    cut(e[tmp - n].to, tmp);
    link(x[i], id[x[i]][y[i]] + n);
    link(y[i], id[x[i]][y[i]] + n);
    

    先给出图的最终态,然后求一个最小生成树

    每个操作先打通链,也就是 (split)

    然后对于询问操作,直接给(s[y])

    对于改边的操作

    每一次加边,都会在生成树上面添加一个环,然后我们找到环上最大边 (cut) 就可以

    (split)已经通链了,所以直接断就可以)

    然后(link)就行了

    Code

    不是很难写吧

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm {
    inline int read() {
        int res = 0, f = 1;
        char k;
        while (!isdigit(k = getchar()))
            if (k == '-')
                f = -1;
        while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
        return res * f;
    }
    const int M = 1e6 + 10, N = 1e5 + 10;
    int f[N], c[N][2], s[N], v[N], st[N], n, m, q, x[N], y[N], opt[N], fa[N], ans[N], id[2010][2010];
    bool r[N];
    struct node {
        int from, to, dis, vis;
        bool operator<(const node &a) const { return dis < a.dis; }
    } e[M];
    inline void push_up(int x) {
        s[x] = max(s[c[x][0]], max(s[c[x][1]], v[x]));
        return;
    }
    inline bool notroot(int x) { return c[f[x]][1] == x || c[f[x]][0] == x; }
    inline void pushr(int x) {
        swap(c[x][0], c[x][1]);
        r[x] ^= 1;
        return;
    }
    inline void push_down(int x) {
        if (r[x]) {
            if (c[x][0])
                pushr(c[x][0]);
            if (c[x][1])
                pushr(c[x][1]);
        }
        return r[x] = 0, void();
    }
    inline void rotate(int tx) {
        int ty = f[tx], z = f[ty], k = (c[ty][1] == tx), w = c[tx][!k];
        if (notroot(ty))
            c[z][c[z][1] == ty] = tx;
        c[tx][!k] = ty;
        c[ty][k] = w;
        if (w)
            f[w] = ty;
        f[ty] = tx;
        f[tx] = z;
        return push_up(ty), push_up(tx);
    }
    inline void splay(int x) {
        int y = x, z = 0;
        st[++z] = y;
        while (notroot(y)) st[++z] = y = f[y];
        while (z) push_down(st[z--]);
        while (notroot(x)) {
            y = f[x], z = f[y];
            if (notroot(y))
                rotate((c[y][0] == x) ^ (c[z][0] == y) ? x : y);
            rotate(x);
        }
        return push_up(y);
    }
    inline void access(int x) {
        for (int y = 0; x; x = f[y = x]) splay(x), c[x][1] = y, push_up(x);
        return;
    }
    inline void makeroot(int x) {
        access(x);
        splay(x);
        pushr(x);
        return;
    }
    inline int findroot(int x) {
        access(x);
        splay(x);
        while (c[x][0]) push_down(x), x = c[x][0];
        splay(x);
        return x;
    }
    inline void split(int x, int y) {
        makeroot(x);
        access(y);
        splay(y);
        return;
    }
    inline void link(int x, int y) {
        makeroot(x);
        if (findroot(y) != x)
            f[x] = y;
        return;
    }
    inline void cut(int x, int y) {
        makeroot(x);
        if (findroot(y) == x && f[y] == x && !c[y][0])
            f[y] = c[x][1] = 0, push_up(x);
        return;
    }
    
    inline int find(int x, int val) {
        if (v[x] == val)
            return x;
        return s[c[x][0]] == val ? find(c[x][0], val) : find(c[x][1], val);
    }
    
    inline int getf(int x) { return x == fa[x] ? x : fa[x] = getf(fa[x]); }
    inline void merge(int x, int y) { fa[getf(x)] = getf(y); }
    inline void Kruskal() {
        for (int i = 1; i <= n; ++i) fa[i] = i;
        for (int i = 1; i <= m; ++i) {
            if (!e[i].vis && getf(e[i].from) != getf(e[i].to)) {
                merge(e[i].from, e[i].to);
                link(e[i].from, n + i);
                link(e[i].to, n + i);
            }
        }
        return;
    }
    
    signed main() {
        n = read();
        m = read();
        q = read();
        for (int i = 1; i <= m; ++i) e[i].from = read(), e[i].to = read(), e[i].dis = read();
        sort(e + 1, e + m + 1);
        for (int i = 1; i <= m; ++i) {
            id[e[i].from][e[i].to] = id[e[i].to][e[i].from] = i;
            v[n + i] = e[i].dis;
        }
        for (int i = 1; i <= q; ++i) {
            opt[i] = read();
            x[i] = read();
            y[i] = read();
            if (opt[i] == 2)
                e[id[x[i]][y[i]]].vis = 1;
        }
        Kruskal();
        int num = 0;
        for (int i = q; i >= 1; --i) {
            split(x[i], y[i]);
            if (opt[i] == 1)
                ans[++num] = s[y[i]];
            else {
                int tmp = find(y[i], s[y[i]]);
                if (v[id[x[i]][y[i]] + n] < s[y[i]]) {
                    cut(e[tmp - n].from, tmp);
                    cut(e[tmp - n].to, tmp);
                    link(x[i], id[x[i]][y[i]] + n);
                    link(y[i], id[x[i]][y[i]] + n);
                }
            }
        }
        for (int i = num; i >= 1; --i) printf("%lld
    ", ans[i]);
        return 0;
    }
    }  // namespace yspm
    signed main() { return yspm::main(); }
    
  • 相关阅读:
    ACM中java的使用
    hdu 1273最大流
    1066N !最右边非零数
    关于为什么要建退边的原因
    浅析指向指针的指针其作用
    poj 1860 bellman 求正环
    poj 3461
    poj 2031
    poj 1068
    strncpy的用法
  • 原文地址:https://www.cnblogs.com/yspm/p/12364992.html
Copyright © 2011-2022 走看看