bzoj4229 选择

Posted iefnah06

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4229 选择相关的知识,希望对你有一定的参考价值。

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")<<'
';
    }
}

以上是关于bzoj4229 选择的主要内容,如果未能解决你的问题,请参考以下文章

VS2008 C ++警告LNK4229:无效指令

VSCode自定义代码片段——CSS选择器

VSCode自定义代码片段6——CSS选择器

Bzoj2339--Hnoi2011卡农

微信小程序代码片段

[bzoj1966][Ahoi2005][VIRUS 病毒检测] (字符串dp)