【bzoj4998】星球联盟(并查集+边双)

编程入门 行业动态 更新时间:2024-10-19 22:30:14

【bzoj4998】<a href=https://www.elefans.com/category/jswz/34/1760928.html style=星球联盟(并查集+边双)"/>

【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]='\n';
}
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]='\n';else merge(st[i].u,st[i].v),print(sz[find(st[i].u)]);return Ot(),0;
}

转载于:.html

更多推荐

【bzoj4998】星球联盟(并查集+边双)

本文发布于:2024-02-07 02:39:45,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1752313.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:星球   联盟   边双

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!