zoukankan      html  css  js  c++  java
  • 【bzoj4998】星球联盟(并查集+边双)

    题面

    传送门

    题解

    总算有自己的(bzoj)账号啦!

    话说这题好像(Scape)去年暑假就讲过……然而我到现在才会……

    (LCT)什么的跑得太慢了而且我也不会,所以这里是一个并查集的做法

    首先题目意思就是要我们动态维护点双

    我们离线,先求出一个森林,并且要使用编号尽量小的边

    连上一条边的时候,如果它们还没有联通,那么显然答案是(No)

    如果已经联通,那么它们这棵树的路径上所有点都会被缩进同一个点双里。暴力的话复杂度显然爆炸

    我们另外开一个并查集(ga),表示(i)所在的边双中深度最小的点,那么每次路径缩点的时候只要改所有边双的深度最小点就可以了

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    char sr[1<<21],z[20];int K=-1,Z=0;
    inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
    void print(R int x){
        if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++K]=z[Z],--Z);sr[++K]='
    ';
    }
    const int N=5e5+5;
    struct eg{int v,nx;}e[N<<1];int head[N],tot;
    inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    struct EG{int u,v,is;}st[N];
    int fa[N],ga[N],sz[N],dep[N],q[N];
    int n,m,p;
    int find(int x){return ga[x]==x?x:ga[x]=find(ga[x]);}
    void bfs(int u){
    	int h=1,t=0;q[++t]=u,dep[u]=1;
    	while(h<=t){
    		u=q[h++];
    		go(u)if(v!=fa[u])fa[v]=u,dep[v]=dep[u]+1,q[++t]=v;
    	}
    }
    void merge(int u,int v){
    	u=find(u),v=find(v);
    	while(u!=v){
    		if(dep[u]<dep[v])swap(u,v);
    		sz[find(fa[u])]+=sz[u],u=ga[u]=ga[fa[u]];
    	}
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	n=read(),m=read(),p=read();
    	fp(i,1,n)ga[i]=i;
    	for(R int i=1,u,v;i<=m+p;++i){
    		u=read(),v=read(),st[i].u=u,st[i].v=v,u=find(u),v=find(v);
    		if(u!=v)ga[u]=v,st[i].is=1,add(st[i].u,st[i].v),add(st[i].v,st[i].u);
    	}
    	fp(i,1,n)if(!dep[i])bfs(i);
    	fp(i,1,n)sz[i]=1,ga[i]=i;
    	fp(i,1,m)if(!st[i].is)merge(st[i].u,st[i].v);
    	fp(i,m+1,m+p)if(st[i].is)sr[++K]='N',sr[++K]='o',sr[++K]='
    ';
    	else merge(st[i].u,st[i].v),print(sz[find(st[i].u)]);
    	return Ot(),0;
    }
    
  • 相关阅读:
    关于回调地狱
    node.js 关于跨域和传递给前台参数
    关于js的当前日期的格式化,和两个日期之间的相减的天数
    CSS 关于让页面的高度达到电脑屏幕的底部
    前端 为什么我选择用框架而不是Jquery
    关于webpack打包图片的路径问题
    关于webpack打包js和css
    微信小程序网络请求的setDate
    WinSocket聊天程序实例(多线程)
    Orcal的JDBC数据连接方式
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10650887.html
Copyright © 2011-2022 走看看