題目大意這樣,給出一些節(jié)點,給出3種命令:
1、將a,b聯(lián)通
2、查詢a,b的聯(lián)通狀況
3、刪除鏈接a的邊。(如果之前a,c通過b聯(lián)通,那么刪除b的聯(lián)通關系后a,c仍然認為聯(lián)通)
1,2兩種操作乍一看MS是并查集,但是第三種狀況讓人很惱火,尤其是想用路徑壓縮技巧的時候。那么,我們不妨轉換下思路,刪除a的聯(lián)通關系可以認為將a節(jié)點重標號,把之前那個a節(jié)點認為是虛擬節(jié)點,這樣聯(lián)通性啥的都好保證了。詳細請看代碼:
Source Code
Problem: 3908 | | User: yzhw |
Memory: 1096K | | Time: 47MS |
Language: G++ | | Result: Accepted |
# include <cstdio>
# define N 100000
using namespace std;
int set[N],id[N];
int find(int pos)
{
if(set[pos]==pos) return pos;
else return set[pos]=find(set[pos]);
}
void uni(int a,int b)
{
set[find(a)]=find(b);
}
int main()
{
int num;
while(scanf("%d",&num)!=EOF)
{
int c=num+1,n1=0,n2=0;
for(int i=1;i<N;i++) set[i]=i;
for(int i=1;i<=num;i++) id[i]=i;
char jud[5];
while(scanf("%s",jud)&&*jud!='e')
{
int a,b;
switch(*jud)
{
case 'c':
scanf("%d%d",&a,&b);
uni(id[a],id[b]);
break;
case 'd':
scanf("%d",&a);
id[a]=c++;
break;
case 'q':
scanf("%d%d",&a,&b);
if(find(id[a])==find(id[b])) n1++;
else n2++;
break;
};
}
printf("%d , %d\n",n1,n2);
}
return 0;
}