有N个齿轮,三种操作
操作L x y:把齿轮x,y链接,若x,y已经属于某个齿轮组中,则这两组也会合并。
操作Q x y:询问x,y旋转方向是否相同(等价于齿轮x,y的相对距离的奇偶性)。
操作D x :拆下齿轮x,并且x所在的齿轮组不会断开
操作S x : 查询齿轮x所在的齿轮组有多少齿轮。
其实就是并查集了,维护父节点的同时,记录一下每个节点到根节点的距离,并且记录一下以x为根节点的集合有多少个元素。由于涉及到删除操作,删除的是根节点的话会导致信息丢失,所以在删除的时候直接新建一个节点,所以再加一个变量,表示节点x所对应的实际节点编号mp[x]。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=660000;
int fa[maxn],dis[maxn],size[maxn],mp[maxn];
int n,m;
int vp;
int find(int x)
{
if (x!=fa[x])
{
int tx=find(fa[x]);
dis[x]+=dis[fa[x]];
return fa[x]=tx;
}
else
return x;
}
int main()
{
// freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
for (int i=1; i<=n+m; i++)
{
fa[i]=mp[i]=i;
dis[i]=0;
size[i]=1;
}
vp=n;
char cmd[12];
int x,y,z;
for (int i=1; i<=m; i++)
{
scanf("%s",cmd);
if (cmd[0]=='L')
{
scanf("%d%d",&x,&y);
x=mp[x];
y=mp[y];
int tx=find(x);
int ty=find(y);
if (tx!=ty)
{
fa[tx]=ty;
size[ty]+=size[tx];
dis[tx]=dis[ty]+1;
dis[x]=dis[y]+1;
}
}
else if (cmd[0]=='Q')
{
scanf("%d%d",&x,&y);
x=mp[x];
y=mp[y];
if (find(x)!=find(y)) puts("Unknown");
else
{
if ((dis[x]-dis[y])&1) puts("Different");
else puts("Same");
}
}
else if (cmd[0]=='S')
{
scanf("%d",&x);
x=mp[x];
printf("%d\n",size[find(x)]);
}
else
{
scanf("%d",&x);
int xx=mp[x];
int tx=find(xx);
size[tx]--;
mp[x]=++vp;
}
}
}
return 0;
}