码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj4229 选择

时间:2020-02-11 09:44:42      阅读:55      评论:0      收藏:0      [点我收藏+]

标签:sig   url   一个   include   vector   other   r++   info   tin   

URL

https://www.lydsy.com/JudgeOnline/problem.php?id=4229

简要题意

给一个无向图。
多次询问,每次删掉一条边,或者询问两个点是否在同一个边双连通分量内。

解法

倒着做。
先只保留所有操作结束后剩下的边,建出边双连通分量对应的森林。
然后倒序加边,每次要么是合并两个树,要么是把一条路径上的点都缩到同一个双连通分量里。

实现

#include <bits/stdc++.h>
using namespace std;

#define rng(i,a,b) for(int i=int(a);i<int(b);i++)
#define gnr(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define rep(i,b) rng(i,0,b)
#define per(i,b) gnr(i,0,b)
#define pb push_back
#define mp make_pair
#define a first
#define b second
#define all(x) (x).begin(),(x).end()
#define si(x) int((x).size())

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef pair<int,int> pi;
typedef vector<int> vi;

template<class t,class u> void chmax(t&a,u b){if(a<b)a=b;}
template<class t,class u> void chmin(t&a,u b){if(b<a)a=b;}

struct unionfind{
    vi p;
    unionfind(int n=0):p(n,-1){}
    int find(int a){
        return p[a]<0?a:(p[a]=find(p[a]));
    }
    void mg(int a,int b){
        a=find(a);
        b=find(b);
        if(a!=b)p[a]=b;
    }
    bool same(int a,int b){
        return find(a)==find(b);
    }
};

const int vmax=1.1e5;

struct Q{
    char tp;
    int x,y;
    friend istream&operator>>(istream&i,Q&q){
        i>>q.tp>>q.x>>q.y;
        q.x--,q.y--;
        if(q.x>q.y)swap(q.x,q.y);
        return i;
    }
};
struct E{
    int s;
    bool tp;
    E(){}
    E(int a,int b,bool t):s(a^b),tp(t){}
    int other(int a){
        return a^s;
    }
};

Q qs[vmax];
unionfind u1,u2;

vector<E> info;
vi g[vmax];
int ce=0;

void make(int a,int b,bool t){
    g[a].pb(si(info));
    g[b].pb(si(info));
    info.pb(E(a,b,t));
}

int id[vmax],lo[vmax],cur;
int par[vmax],dep[vmax];

int res[vmax];

void dfs(int v,int p){
    id[v]=lo[v]=cur++;
    rep(z,si(g[v])){
        int e=g[v][z];
        if(e==p)continue;
        int to=info[e].other(v);
        bool tp=info[e].tp;

        if(id[to]==-1){
            dep[to]=dep[v]+1;
            par[to]=v;
            dfs(to,e);
            if(!tp){
                chmin(lo[v],lo[to]);
                if(lo[to]<=id[v])u2.mg(to,v);
            }
        }else if(!tp){
            chmin(lo[v],id[to]);
        }
    }
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n,m,q;cin>>n>>m>>q;
    multiset<pi> es;
    rep(i,m){
        int a,b;cin>>a>>b;
        a--,b--;
        if(a>b)swap(a,b);
        es.insert(pi(a,b));
    }

    rep(i,q){
        cin>>qs[i];
        if(qs[i].tp=='Z')
            es.erase(es.find(pi(qs[i].x,qs[i].y)));
    }

    u1=unionfind(n);
    u2=unionfind(n);
    {
        for(multiset<pi>::iterator it=es.begin();it!=es.end();++it){
            int a=it->a,b=it->b;
            u1.mg(a,b);
            make(a,b,false);
        }
        unionfind tmp=u1;
        gnr(i,0,q)if(qs[i].tp=='Z'){
            int a=qs[i].x,b=qs[i].y;
            if(tmp.same(a,b))continue;
            tmp.mg(a,b);
            make(a,b,true);
        }

        fill(id,id+n,-1);
        fill(par,par+n,-1);
        rep(i,n)if(id[i]==-1)dfs(i,-1);
        assert(n==cur);
    }

    gnr(i,0,q){
        int a=qs[i].x,b=qs[i].y;
        if(qs[i].tp=='Z'){
            if(!u1.same(a,b)){
                if(dep[a]<dep[b])swap(a,b);
                u1.mg(a,b);
            }else{
                while(true){
                    a=u2.find(a);
                    b=u2.find(b);
                    if(a==b)break;
                    if(dep[a]<dep[b])swap(a,b);
                    u2.mg(a,par[a]);
                    a=par[a];
                }
            }
        }else{
            res[i]=u2.same(a,b);
        }
    }

    rep(i,q)if(qs[i].tp=='P'){
        cout<<(res[i]?"Yes":"No")<<'\n';
    }
}

bzoj4229 选择

标签:sig   url   一个   include   vector   other   r++   info   tin   

原文地址:https://www.cnblogs.com/iefnah06/p/12293611.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!