bzoj3237 [Ahoi2013]连通图

Posted 逢山开路 遇水架桥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n", 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

 

以上是关于bzoj3237 [Ahoi2013]连通图的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3237 [Ahoi2013]连通图

BZOJ3237: [Ahoi2013]连通图

3237: [Ahoi2013]连通图 线段树分治

随机算法瞎练BZOJ3237&3563&3569三倍经验题

[BZOJ1969][AHOI2005]LANE 航线规划

BZOJ[1969] [Ahoi2005]LANE 航线规划