• bzoj3237 [Ahoi2013]连通图


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3237

    【题解】

    先写了一个对询问分治然后不断加边的分治。

    发现有可能一条边在几乎每个分治区间都会判,就gg了。

    然后get一个比较正常的idea,就是我计算总删边次数cnt,先把没删的添加到边集中。

    在分治[l,r]的时候,考虑[l,mid]对[mid+1,r]的影响,把[l,mid]删过的边先在cnt里扣去。

    每当一个数被扣到0,也就是意思是在[mid+1,r]没被删了,就加到边集中,递归分治[mid+1,r]

    否则就撤回刚刚的操作,用[mid+1,r]对[l,mid]做一遍。

    复杂度O(nlog^2n)

    这样实质还是边有没有用到的问题,只是一个小小的实现技巧。

    # include <stdio.h>
    # include <assert.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10, N = 1e6 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, m, del[M];
    
    struct edge {
        int u, v;
        edge() {}
        edge(int u, int v) : u(u), v(v) {}
        inline void set() {
            scanf("%d%d", &u, &v);
        }
    }t[M], e[M];
    
    struct quest {
        int c, p[5];
        inline void set() {
            scanf("%d", &c);
            for (int i=1; i<=c; ++i) {
                scanf("%d", &p[i]);
                del[p[i]] ++;
            }
        }
    }q[M];
    
    
    int st[N], stn=0;
    
    struct us {
        int n, fa[M], rk[M];
        inline void set(int _n) {
            n = _n;
            for (int i=1; i<=n; ++i) fa[i] = i, rk[i] = 1;
        }
        inline int getf(int x) {
            return fa[x] == x ? x : getf(fa[x]);
        }
        inline void un(int x, int y) {
            x = getf(x), y = getf(y);
            if(x == y) return;
            if(rk[x] > rk[y]) swap(x, y);
            if(rk[x] == rk[y]) ++rk[y], st[++stn] = -y;
            fa[x] = y; st[++stn] = x;
            -- n;
        }
        inline void re() {
            int x = st[stn]; --stn;
            if(x<0) -- rk[-x];
            else fa[x] = x, ++ n;
        }
    }E;
    
    bool ans[M];
    bool u[M];
    
    inline void solve(int ql, int qr) {
    //    cout << ql << ' ' << qr << ' ' << E.n << endl;
        if(E.n == 1) {
            for (int i=ql; i<=qr; ++i) ans[i] = 1;
            return ;
        }
        if(ql == qr) return ;
        int qmid = ql + qr >> 1, cur_stn = stn;
        for (int i=ql, ps; i<=qmid; ++i) 
            for (int j=1; j<=q[i].c; ++j) {
                --del[ps = q[i].p[j]];
                if(del[ps] == 0) E.un(e[ps].u, e[ps].v);
            }
        solve(qmid+1, qr);
        for (int i=ql; i<=qmid; ++i) 
            for (int j=1; j<=q[i].c; ++j) ++del[q[i].p[j]];
        while(stn != cur_stn) E.re();
        for (int i=qmid+1, ps; i<=qr; ++i) 
            for (int j=1; j<=q[i].c; ++j) {
                --del[ps = q[i].p[j]];
                if(del[ps] == 0) E.un(e[ps].u, e[ps].v);
            }
        solve(ql, qmid);
        for (int i=qmid+1; i<=qr; ++i) 
            for (int j=1; j<=q[i].c; ++j) ++del[q[i].p[j]];
        while(stn != cur_stn) E.re();
    }
    
    int main() {
        int en = 0;
        cin >> n >> m; E.set(n);
        for (int i=1; i<=m; ++i) e[i].set();
        int Q; cin >> Q;
        for (int i=1; i<=Q; ++i) q[i].set();
        for (int i=1; i<=m; ++i) if(!del[i]) E.un(e[i].u, e[i].v);
        solve(1, Q);
        for (int i=1; i<=Q; ++i) puts(ans[i] ? "Connected" : "Disconnected");
        return 0;
    }
    View Code

    下面这份代码是我之前的思路,会T(废话)

    # include <map>
    # include <stdio.h>
    # include <assert.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10, N = 1e6 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, m;
    map< pair<int,int>, bool > mp;
    
    struct edge {
        int u, v;
        edge() {}
        edge(int u, int v) : u(u), v(v) {}
        inline void set() {
            scanf("%d%d", &u, &v);
        }
    }t[M], e[M];
    
    struct quest {
        int c, u[5], v[5];
        inline void set() {
            scanf("%d", &c);
            for (int i=1, t; i<=c; ++i) {
                scanf("%d", &t);
                u[i] = e[t].u, v[i] = e[t].v;
            }
        }
    }q[M];
    
    
    int st[N], stn=0;
    
    struct us {
        int n, fa[M], rk[M];
        inline void set(int _n) {
            n = _n;
            for (int i=1; i<=n; ++i) fa[i] = i, rk[i] = 1;
        }
        inline int getf(int x) {
            return fa[x] == x ? x : getf(fa[x]);
        }
        inline void un(int x, int y) {
            x = getf(x), y = getf(y);
            if(x == y) return;
            if(rk[x] > rk[y]) swap(x, y);
            if(rk[x] == rk[y]) ++rk[y], st[++stn] = -y;
            fa[x] = y; st[++stn] = x;
            -- n;
        }
        inline void re() {
            int x = st[stn]; --stn;
            if(x<0) -- rk[-x];
            else fa[x] = x, ++ n;
        }
    }E;
    
    bool ans[M];
    bool u[M];
    
    inline void add(int u, int v) {
        mp[make_pair(u, v)] = 1;
        mp[make_pair(v, u)] = 1;
    }
    inline bool query(int u, int v) {
        return mp.find(make_pair(u, v)) == mp.end();
    }
    
    inline void solve(int ql, int qr, int er) {
        int cur_stn = stn, tn = 0, ps;
        for (int i=ql; i<=qr; ++i)
            for (int j=1; j<=q[i].c; ++j) add(q[i].u[j], q[i].v[j]);
        for (int i=1; i<=er; ++i)
            if(u[i] = query(e[i].u, e[i].v)) E.un(e[i].u, e[i].v);
        mp.clear();
    //    printf("ql = %d, qr = %d, E.n = %d
    ", ql, qr, E.n);
        if(E.n == 1) {
            for (int i=ql; i<=qr; ++i) ans[i] = 1;
            while(stn != cur_stn) E.re();
            return ;
        }
        if(ql == qr) {
            while(stn != cur_stn) E.re();
            return ;
        }
        for (int i=1; i<=er; ++i) if(!u[i]) t[++tn] = e[i]; ps = tn;
        for (int i=1; i<=er; ++i) if(u[i]) t[++tn] = e[i];
        for (int i=1; i<=er; ++i) e[i] = t[i];
        int qmid = ql + qr >> 1;
        solve(ql, qmid, ps);
        solve(qmid+1, qr, ps);
        while(stn != cur_stn) E.re();
    }
    
    int main() {
        int en = 0;
        cin >> n >> m; E.set(n);
        for (int i=1; i<=m; ++i) e[i].set();
        int Q; cin >> Q;
        for (int i=1; i<=Q; ++i) q[i].set();
        solve(1, Q, m);
        for (int i=1; i<=Q; ++i) puts(ans[i] ? "Connected" : "Disconnected");
        return 0;
    }
    View Code
  • 相关阅读:
    LC 综合 中级算法笔记
    LC 212. 单词搜索2
    [NLP] 2.2 文本正规化 (Text Normalization)
    本地秘钥复制到github,实现两者之间的交互
    Python 实例化对象
    C# 左补齐+ 生成一个星期的日期
    hello world
    迭代器模式、观察者模式
    代理模式、桥接模式、装饰器模式、适配器模式
    外观模式、组合模式、享元模式
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3237.html
Copyright © 2020-2023  润新知