题意:
有n个编号分别为1~n的立方体以及两种操作,一种是move操作,一种是count操作。move操作就是让你把含x的一堆立方体移到含y的一堆立方体的上面,count操作就是让你求出编号为x的立方体底下有几个立方体。
解析:
一看到这道题,很容易就能想到用并查集来做,而这道题也的确是用并查集来做的O(∩_∩)O~
首先,我们先来考虑move操作。当你要把两堆立方体堆在一起时,可以把底下那堆的堆顶的father更新为上面那堆的堆顶,这应该是很容易想到的。
那么,应该如何求出编号为x的立方体底下的方块数呢?
我们可以用Under[x]来记录编号为x的立方体底下有多少个方块,这样,输出时只要输出Under[x]即可。
可是我们不可能持续更新Under[x],这样的复杂度太大了,因此,我们可以用一个Up[]数组来记录每个立方体到它所在的那堆立方体的堆顶的距离,这样只要持续更新每一堆的堆顶的Under[]值即可。
而这一步只需在合并时就能顺便完成了,几乎无需任何复杂度。
并且,Up[]数组的更新也是非常容易的,只需在并查集函数getfa()中加一句Up[x]+=Up[f[x]]即可。
这样一来,就可以发现Under[x]=Under[getfa(x)]-Up[x],因此输出时只要输出Under[getfa(x)]-Up[x]就可以了。
代码如下:
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #define max(x,y) (x>y?x:y) #define min(x,y) (x<y?x:y) #define N 30000 #define M 100000 using namespace std; int m,f[N+5],Up[N+5],Under[N+5]; int read() { int x=0,f=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if(ch=='-') f=-1,ch=getchar(); while(ch>='0'&&ch<='9') (x*=10)+=ch-'0',ch=getchar(); return x*=f; } void write(int x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } int getfa(int x)//并查集函数 { if(f[x]==x) return x; int fx=getfa(f[x]); Up[x]+=Up[f[x]],f[x]=fx;//更新f[]和Up[]两个数组 return f[x]; } int main() { for(int i=1;i<=N;i++) f[i]=i,Up[i]=Under[i]=0;//初始化 m=read(); for(int i=1;i<=m;i++) { char ch; cin>>ch; if(ch=='M') { int x=read(),y=read(),fx=getfa(x),fy=getfa(y); Up[fy]=Under[fx]+1,(Under[fx]+=Under[fy])++,f[fy]=fx;//更新上面一堆堆顶的Under[]值以及下面一堆堆顶的father } if(ch=='C') { int x=read(),fx=getfa(x); write(Under[fx]-Up[x]),putchar('\n');//输出 } } return 0; }
版权声明:转载请注明地址