poj1988(判断一个结点下面有多少个结点,推荐)
题意:有n个元素,开始每个元素自己一栈,有两种操作,将含有元素x的栈放在含有y的栈的顶端,合并为一个栈。第二种操作是询问含有x元素下面有多少个元素。
6 M 1 6 C 1 M 2 4 M 2 6 C 3 C 4
输出:
1 0 2
思路:这道题,说不上很难,额,解决它也的确花了比较长的时间。询问x元素下面有多少个元素,那么我只需要统计x元素上面有多少个元素,再用x所在的并查集的根节点的元素个数减去x元素上面的元素个数,
结果就出来了......当然,还是有些细节地方要说说的,在路径压缩的时候,有个rang[][3],其中rank[x][0],代表元素x上面有多少个元素,rank[x][1]代表元素x下面有多少个元素,rank[x][2]判断x元素
是否为某个子并查集的根节点。
如果某个结点x的父亲结点y曾经为某一个子并查集的根节点,那么,说明对于这个结点x已经是在y为根节点的时候压缩过了,那么当y不为根节点了,就不必再重新x对y的路径了,只需要直接更新,x对于新的根节点的路径
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int father[30005],rank[30005][3];
int flag=0;
int find(int x)
{
if(rank[x][0]==0)
rank[x][2]=1;
if(x==father[x])
return x;
int tmp=father[x];
father[x]=find(father[x]);
int root=father[x];
if(tmp==root)
{
rank[root][1]+=rank[x][1];
rank[x][1]=0;
//if(rank[root])
/*if(flag==1)
{
printf("1: %d %d %d %d\n",x,tmp,rank[x][0],rank[tmp][0]);
}*/
}
else
{
rank[root][1]+=rank[x][1];
rank[x][1]=0;
if(rank[tmp][2]==1) //曾经为某一颗子并查集的根结点,那么它下面的结点直接+上根节点的值就是
rank[x][0]+=rank[tmp][0];
else
rank[x][0]=rank[tmp][0]+1;
/*if(flag==1)
{
printf("2: %d %d %d %d\n",x,tmp,rank[x][0],rank[tmp][0]);
}*/
}
return root;
}
void liantong(int tmp,int tmp1)
{
int x=find(tmp);
int y=find(tmp1);
father[y]=x;
rank[y][0]=rank[x][1];
rank[x][1]+=rank[y][1];
rank[y][1]=0;
}
int main()
{
int n;
scanf("%d",&n);
{
for(int i=0; i<=30001; i++)
{
father[i]=i;
rank[i][0]=0;
rank[i][1]=1;
rank[i][2]=0;
}
while(n--)
{
char ch[10];
scanf("%s",ch);
if(ch[0]=='M')
{
int tmp,tmp1;
scanf("%d%d",&tmp,&tmp1);
int x=find(tmp);
int y=find(tmp1);
if(x!=y)
liantong(tmp,tmp1);
// find(tmp);
// find(tmp1);
}
else
{
int k;
scanf("%d",&k);
if(k==17)
flag=1;
int ans=rank[find(k)][1];
/*if(rank[k][0]==0)
printf("%d\n",rank[k][1]-1);
else*/
printf("%d\n",ans-rank[k][0]-1);
}
}
}
return 0;
}
/*
110
M 12 14
M 15 16
M 16 17
M 12 17
C 17
*/
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。

浙公网安备 33010602011771号