G:Dance Mooves I
题意:
n头牛排成一排,初始时编号为i的牛在第i个位置
有k次交换,每次会交换a,b两个位置的牛
这k次交换将按顺序,无限循环执行下去
最后问每头牛能够到达的位置的个数
题解:
可以先按照题意模拟一遍,求出k次交换后每头牛所在位置p[i],并记录在这k次交换中每头牛到过的地点的集合
题目要求无限次循环交换,但可以发现,加入编号为i的牛经过一遍交换后到达位置j,编号为j的牛经过一遍交换后到达位置k,那么编号为i的牛在经过两遍交换后也能够到达位置k(路径继承性)
所以可以借助并查集,将所有的x与p[x]合并,那么对于每个独立的集合,集合中的奶牛所能到达的地点是可以共享的
最后枚举每个集合,再借助O(n)的set遍历,通过bitset来快速标记每个位置是否可到达,最后用count(bitset中1的个数)来表示这个集合中每头牛所能到达的位置数量
int n,m;
int a[100060];
int fa[100060];
set<int>s[100060];
int vis[100060];
int ans[100060];
vector<int>mp[100050];
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void join(int x,int y){
if(x==y)return ;
x=find(x),y=find(y);
fa[max(x,y)]=min(x,y); //往编号小的集合合并,方便遍历
}
int main(){
n=qread(),m=qread();
for(int i=1;i<=n;i++){
fa[i]=i;
a[i]=i;
s[i].insert(i);
}
for(int i=1;i<=m;i++){
int k1=qread(),k2=qread();
s[a[k1]].insert(k2); //编号为a[x]的牛会到达位置y
s[a[k2]].insert(k1);
swap(a[k1],a[k2]);
}
for(int i=1;i<=n;i++){
join(a[i],i);
}
for(int i=1;i<=n;i++){
mp[find(i)].push_back(i); //记录每个集合内的牛的编号
}
bitset<100010> bs;
for(int i=1;i<=n;i++){
if(vis[i])
continue;
bs.reset();
for(int g:mp[i]){
vis[g]=1;
for(int id:s[g]){
bs.set(id);
}
}
ans[i]=bs.count();
}
for(int i=1;i<=n;i++){
printf("%d\n",ans[find(i)]);
}
return 0;
}
第一次用在比赛中遇到 bitset 还是不会,555
解法二,跳过bitset,用启发式合并
int n,m;
int a[100060];
int fa[100060];
int ans[100060];
int k1[200060],k2[200060];
map<ll,int>mp;
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
void join(int x,int y){
if(x==y)return ;
x=find(x),y=find(y);
fa[x]=y;
}
int main(){
mp.clear();
n=qread(),m=qread();
for(int i=1;i<=n;i++){
fa[i]=i;
a[i]=i;
}
for(int i=1;i<=m;i++){
k1[i]=qread(),k2[i]=qread();
swap(a[k1[i]],a[k2[i]]);
}
for(int i=1;i<=n;i++){
join(a[i],i);
}
for(int i=1;i<=n;i++){
a[i]=i;
}
for(int i=1;i<=m;i++){
int x=k1[i],y=k2[i];
ll xx=1LL*find(a[x])*1000000+y,yy=1LL*find(a[y])*1000000+x;
if(!mp[xx]){
mp[xx]=1;
if(find(a[x])!=y)ans[find(a[x])]++;
}
if(!mp[yy]){
mp[yy]=1;
if(find(a[y])!=x)ans[find(a[y])]++;
}
swap(a[k1[i]],a[k2[i]]);
}
for(int i=1;i<=n;i++){
printf("%d\n",ans[find(i)]+1);
}
return 0;
}
还以为不能做的,原来是并查集啊
这道题挺卡并查集的,好像合并的不好,会wa会T
没学明白