【洛谷 P7299】 【并查集】 Dance Mooves S
题目
解题思路
可以先求出k轮后i能到达next[i]
可以发现将会组成由很多个简单环组成的图,它们能到达的点可以共享给同一个环内的
所以可以用并查集统计出每一个环,暴力合并环内点能到达的点集
代码
#include<iostream>
#include<vector>
#include<cstdio>
#include<bitset>
#include<set>
using namespace std;
int n,k,x,y,c[100020],fa[100010],vis[100010],ans[100010];
set<int> st[100010];
vector<int> g[100010];
bitset<100010> p; //相当于一个bool类型的数组
int find(int x)
{
if (x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
int main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++)
{
c[i]=i;
fa[i]=i;
st[i].insert(i);
}
for (int i=1;i<=k;i++) //求k轮后i到达的点,以及每一个点经过的点集
{
scanf("%d%d",&x,&y);
st[c[x]].insert(y);
st[c[y]].insert(x);
swap(c[x],c[y]);
}
for (int i=1;i<=n;i++) //并查集统计环
{
int fx=find(i),fy=find(c[i]);
if (fx!=fy)
fa[max(fx,fy)]=min(fx,fy);
}
for (int i=1;i<=n;i++)
g[find(i)].push_back(i);
for (int i=1;i<=n;i++)
{
if (vis[i]) continue;
p.reset(); //全部清0
while (!g[i].empty())
{
x=g[i].back(); //取出最后一个数
g[i].pop_back(); //删去最后一个
vis[x]++;
int j;
while (st[x].size()) //暴力合并点集
{
j=*st[x].begin(); //取第一个值
st[x].erase(st[x].begin()); //删第一个
p.set(j); //将第j为变为1
}
}
ans[i]=p.count(); //统计1的个数,就是经过了多少个点
}
for (int i=1;i<=n;i++) printf("%d\n",ans[find(i)]);
return 0;
}