您的位置:首页 > 其它

1159. 【NOI2002】银河英雄说(并查集)

2017-08-21 12:45 260 查看

The link :

https://jzoj.net/junior/#main/show/1826

Problem

给定T条指令,每次指令有合并,询问两种操作,如果是合并,就把对应的两条边合并到一个集合中,如果是询问,则询问两点是否在同一个集合,如果是,输出两点之间的距离,否则输出-1.

Data constraint

1<=T<=500,000

1<=i , j<=30000

Solution

注意这道题的一个关键,这是一条链,虽然还是得用路径压缩,但不能按秩合并,每次一定是连到末尾,那么这样子我们只需要维护一个深度和一个高度,每次在找父亲时更新即可.

深度:从根节点往下的路径数.

高度:从一个节点到叶节点的最长路径数.

所以每次拿高度去更新深度即可.

#include <iostream>
#include <cstdio>
#include <cstring>

#define Maxn 500001

using namespace std;

char ch[1];

int T,i,x,y,xx,yy,fa[Maxn],sum[Maxn],deep[Maxn];

int abs(int x) { if (x>0) return x; else return -x; }

int getfather(int x)
{
if (fa[x]==0) return x;
int get=getfather(fa[x]);
deep[x]+=deep[fa[x]],fa[x]=get;
return get;
}

void merge(int x,int y)
{
xx=getfather(x),yy=getfather(y);
fa[xx]=yy,deep[xx]+=sum[yy],sum[yy]+=sum[xx];
}

void Query(int x,int y)
{
xx=getfather(x),yy=getfather(y);
if (xx!=yy) printf("-1\n"); else printf("%d\n",abs(deep[x]-deep[y])-1);
}

int main()
{
scanf("%d",&T);
for (i=1;i<=30000;i++) sum[i]=1;
for (i=1;i<=T;i++)
{
scanf("%s %d %d",ch,&x,&y);
if (ch[0]=='M')
merge(x,y);
else
Query(x,y);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: