这题和1703几乎是一样的,就是看两个点之间的点是偶数还是基数,关键是记录下每一个点的权数(即每一点在树中的层数)。。。
比如像两个串1-2-3和 4-5-6-7,如果吧2和6连,那么怎么去改变合成串中个点的权数是个头疼的问题,只要这个问题解决,那么问题也就迎刃而解了。
典型思路,用fa[i]代表i的父节点,这里进行路径压缩,所以每个i的父节点都是它所在的树的根结点。。用pv[i]代表i的权数,也就是节点i所处在树中的层数(其实由于路径压缩,所有的树就只有两层,一层是根结点,一层是子节点,但是为了计算,把每一节点应该所在的层记下了)。。。
那么,核心代码为:
void init(int n){
int i;
for(i=0;i<=n;i++){
fa[i]=-1; //初始化每一节点的父节点都是-1,每一点的层数都是0;
pv[i]=0;
}
}
int find(int i){
int r;
if(fa[i]<0)
return i; //若i为根结点,则返回i的值
r=find(fa[i]); //寻找i的根结点
pv[i]+=pv[fa[i]]; //注意这不很重要,如果是一个点一个点的加,则这一步没什么作用,因为fa[i]肯定是根结点,其权数为0,但若出现两个树的子节点相连,如1-2-3,4-5-6-7.然后3和6 相连,就很重要,因为连完后,4的权数变为2,而567的全书也要变化,这一变化不是直接就变的,而是通过以后每一次find操作,给567加上2,形成相连后的层数!!!
fa[i]=r;
return r;
}
void unit(int a,int b){
int ra=find(a); //通过find 操作,把a,b的权数调整为争取的权数。
int rb=find(b);
if(pv[a]>pv[b]){ //若是1-2,连接2-3,就必须要判断2和3的权数大小,要不然输入2,3和输入3,2会得到不同的答案。。。
fa[rb]=ra;
pv[rb]=pv[a]-pv[b]+1;
}
else{
fa[ra]=rb;
pv[ra]=pv[b]-pv[a]+1;
}
}
AC代码:
#include<stdio.h>
#define m1 2005
int fa[m1],pv[m1];
void init(int n){
int i;
for(i=0;i<=n;i++){
fa[i]=-1;
pv[i]=0;
}
}
int find(int i){
int r;
if(fa[i]<0)
return i;
r=find(fa[i]);
pv[i]+=pv[fa[i]];
fa[i]=r;
return r;
}
void unit(int a,int b){
int ra=find(a);
int rb=find(b);
if(pv[a]>pv[b]){
fa[rb]=ra;
pv[rb]=pv[a]-pv[b]+1;
}
else{
fa[ra]=rb;
pv[ra]=pv[b]-pv[a]+1;
}
}
void main(){
int i,n1,a,b,count=0,flag,m,n;
scanf("%d",&n1);
while(n1--){
flag=1;
count++;
scanf("%d%d",&n,&m);
init(n);
for(i=0;i<m;i++){
scanf("%d%d",&a,&b);
if(flag){
if(find(a)!=find(b))
unit(a,b);
else{
if((pv[a]+pv[b])%2==0){
printf("Scenario #%d:/nSuspicious bugs found!/n/n", count);
flag=0;
}
}
}
}
if(flag)
printf ( "Scenario #%d:/nNo suspicious bugs found!/n/n", count );
}
}
同一类型的题目还有1988cube stacking:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1988
ac代码:
#include<stdio.h>
#define MAX 30001
int fa[MAX],down[MAX],up[MAX];
void init(){
int i;
for(i=0;i<MAX;i++){
fa[i]=i;
down[i]=1;
up[i]=0;
}
}
void link(int x,int y){
fa[y]=x;
up[y]=down[x];
down[x]+=down[y];
}
int getup(int top,int a){
if(fa[a]!=top){
up[a]+=getup(top,fa[a]);
fa[a]=top;
}
return up[a];
}
int find(int i){
int r;
if(fa[i]!=i){
r=find(fa[i]);
getup(r,i); //同样这里每一次find操作都会把需要改变的up[i]的值改变掉。。
}
return fa[i];
}
void unit(int x,int y){
link(find(x),find(y));
}
void main(){
int i,n,a,b;
char c;
scanf("%d",&n);
init();
while(n--){
getchar();
scanf("%c",&c);
if(c=='M'){
scanf("%d%d",&a,&b);
unit(a,b);
}
else if(c=='C'){
scanf("%d",&a);
printf("%d/n",down[find(a)]-up[a]-1);
}
}
}
并查集其它题:http://acm.pku.edu.cn/JudgeOnline/problem?id=1611 the suspect
http://acm.pku.edu.cn/JudgeOnline/problem?id=2985 The k-th Largest Group (未完成)