bzoj4998: 星球联盟
被gc巨侠D飞来做这题,好恶心,还不让人在线LCT T_T (其实明明就是你忘了强行甩锅)
xgc:并查集乱搞就能过写什么LCT
动态维护双联通分量
我们离线做......
首先做一次最小生成树,构出搜索树
然后没有用到的边就拿去暴力合并环,用并查集跳着找
完了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[810000];int len,last[210000]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int fa[2][210000]; int findfa(int x,int w) { if(fa[w][x]<0)return x; fa[w][x]=findfa(fa[w][x],w);return fa[w][x]; } int dep[210000]; void dfs(int x) { for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(dep[y]==0) dep[y]=dep[x]+1, fa[0][y]=x, dfs(y); } } int Link(int x,int y) { int fx=findfa(x,1),fy=findfa(y,1); if(fx!=fy) { int tot=0; x=fx,y=fy; while(x!=y) { if(dep[x]<dep[y])swap(x,y); tot+=fa[1][x]; fa[1][x]=findfa(fa[0][x],1); x=fa[1][x]; } fa[1][x]+=tot; } return -fa[1][findfa(x,1)]; } struct edge{int x,y;}e[410000]; bool v[410000]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n,m,Q,x,y; scanf("%d%d%d",&n,&m,&Q); for(int i=1;i<=n;i++)fa[1][i]=-1; len=1;memset(last,0,sizeof(last)); memset(v,false,sizeof(v)); for(int i=1;i<=m+Q;i++) { scanf("%d%d",&e[i].x,&e[i].y); int fx=findfa(e[i].x,1),fy=findfa(e[i].y,1); if(fx!=fy) { v[i]=true; fa[1][fx]=fy; ins(e[i].x,e[i].y), ins(e[i].y,e[i].x); } } memset(dep,0,sizeof(dep)); for(int i=1;i<=n;i++) if(dep[i]==0) dep[i]=1, fa[0][i]=0, dfs(i); for(int i=1;i<=n;i++)fa[1][i]=-1; for(int i=1;i<=m+Q;i++) { if(v[i]==true) { if(i>m)printf("No\n"); } else { int d=Link(e[i].x,e[i].y); if(i>m) { if(d==-1)printf("No\n"); else printf("%d\n",d); } } } return 0; }
pain and happy in the cruel world.