[BZOJ]4998: 星球联盟
题解: LCT+并查集 查询环上元素个数
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define pii pair<int,int> #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=3e5+10; const double eps=1e-8; #define ll long long using namespace std; struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e; void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;} ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } int f[MAXN]; int find1(int x){ if(x==f[x])return x; return f[x]=find1(f[x]); } int pre[MAXN],ch[MAXN][2],res[MAXN],sz[MAXN]; bool rt[MAXN]; void newnode(int t){ pre[t]=ch[t][0]=ch[t][1]=res[t]=0;rt[t]=1; } void reverse(int x){ if(!x)return ; swap(ch[x][0],ch[x][1]); res[x]^=1; } void push(int x){ if(res[x]){ reverse(ch[x][0]); reverse(ch[x][1]); res[x]^=1; } } void P(int x){ if(!rt[x])P(find1(pre[x])); push(x); } void rotate(int x,int kind){ int y=find1(pre[x]); ch[y][!kind]=ch[x][kind];pre[ch[x][kind]]=y; if(rt[y])rt[x]=1,rt[y]=0; else ch[find1(pre[y])][ch[find1(pre[y])][1]==y]=x; pre[x]=find1(pre[y]);ch[x][kind]=y;pre[y]=x; } void splay(int x){ P(x); while(!rt[x]){ if(rt[find1(pre[x])])rotate(x,ch[find1(pre[x])][0]==x); else{ int y=find1(pre[x]);int kind=ch[find1(pre[y])][0]==y; if(ch[y][kind]==x)rotate(x,!kind),rotate(x,kind); else rotate(y,kind),rotate(x,kind); } } } void access(int x){ int y=0; while(x){ splay(x); if(ch[x][1])pre[ch[x][1]]=x,rt[ch[x][1]]=1,ch[x][1]=0; if(y)rt[y]=0; ch[x][1]=y; y=x;x=find1(pre[x]); } } void mroot(int x){access(x);splay(x);reverse(x);} void Link(int x,int y){ x=find1(x);y=find1(y); mroot(x);mroot(y); pre[x]=y; } bool pd(int u,int v){ u=find1(u);v=find1(v); while(pre[u])u=find1(pre[u]); while(pre[v])v=find1(pre[v]); return u==v; } int st[MAXN],tot; void dfs(int x){ if(!x)return ; st[++tot]=x;push(x); dfs(ch[x][0]); dfs(ch[x][1]); } void Tarjan(int u,int v){ u=find1(u);v=find1(v); if(u==v)return ; mroot(u);access(v);splay(v); tot=0;dfs(v); inc(i,2,tot){ int t1=find1(st[i-1]); int t2=find1(st[i]); if(t1==t2)continue; f[t2]=t1;sz[t1]+=sz[t2]; } inc(i,1,tot)ch[st[i]][0]=ch[st[i]][1]=pre[st[i]]=0,rt[st[i]]=1; } int main(){ int n=read();int m=read();int q=read(); inc(i,1,n)newnode(i),f[i]=i,sz[i]=1; int u,v; inc(i,1,m){ u=read();v=read(); if(!pd(u,v))Link(u,v); else Tarjan(u,v); } inc(i,1,q){ u=read();v=read(); if(!pd(u,v))printf("No\n"),Link(u,v); else{ Tarjan(u,v); int t1=find1(u); printf("%d\n",sz[t1]); } } }
4998: 星球联盟
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 329 Solved: 195
[Submit][Status][Discuss]
Description
在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。但是,组成
联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能
够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有
公共隧道的路径。为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条
新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨
道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。
Input
第1行三个整数N,M和P,分别表示总星球数,初始时太空隧道的数目和即将建设的轨道数目。
第2至第M+1行,每行两个整数,表示初始时的每条太空隧道连接的两个星球编号。
第M+2行至第M+P+1行,每行两个整数,表示新建的太空隧道连接的两个星球编号。
这些太空隧道按照输入的顺序依次建成。
1≤N,M,P≤200000
Output
输出共P行。
如果这条新的太空隧道连接的两个星球属于同一个联盟,就输出一个整数,表示这两个星球所在联盟的星球数。
如果这条新的太空隧道连接的两个星球不属于同一个联盟,就输出"No"(不含引号)。
Sample Input
5 3 4
1 2
4 3
4 5
2 3
1 3
4 5
2 4
1 2
4 3
4 5
2 3
1 3
4 5
2 4
Sample Output
No
3
2
5
3
2
5
HINT