238. 银河英雄传说 (带边权的并查集)

有一个划分为N列的星际战场,各列依次编号为1,2,…,N。

有N艘战舰,也依次编号为1,2,…,N,其中第i号战舰处于第i列。

有T条指令,每条指令格式为以下两种之一:

1、M i j,表示让第i号战舰所在列的全部战舰保持原有顺序,接在第j号战舰所在列的尾部。

2、C i j,表示询问第i号战舰与第j号战舰当前是否处于同一列中,如果在同一列中,它们之间间隔了多少艘战舰。

现在需要你编写一个程序,处理一系列的指令。

输入格式

第一行包含整数T,表示共有T条指令。

接下来T行,每行一个指令,指令有两种形式:M i j或C i j。

其中M和C为大写字母表示指令类型,i和j为整数,表示指令涉及的战舰编号。

输出格式

你的程序应当依次对输入的每一条指令进行分析和处理:

如果是M i j形式,则表示舰队排列发生了变化,你的程序要注意到这一点,但是不要输出任何信息;

如果是C i j形式,你的程序要输出一行,仅包含一个整数,表示在同一列上,第i号战舰与第j号战舰之间布置的战舰数目,如果第i号战舰与第j号战舰当前不在同一列上,则输出-1。

数据范围

N≤30000,T≤500000N≤30000,T≤500000

输入样例:

4
M 2 3
C 1 2
M 2 4
C 4 2

输出样例:

-1
1

 引言 : 一条链也是一颗树。

 Mij的含义是 把 i 接到 j后。

在原有并查集的基础上,增加一个d[ ] 数组,记录x 与 pre[x]之间的边的权值,在路径压缩的把x 直接指向树根的同时,我们把d[x]更新为从x到树根的路径上的所有边权之和。然后 j - i 的边权就应该是合并之前集合j的大小,所以在增加一个Size[ ] 数组记录集合的大小。

AC Code:

#include
#define LL long long
#define ULL  unsigned  long long
#define maxn (LL)1e5
#define INF 0x3f3f3f3f
#define inf 0x7fffffff
#define PI  acos(-1.0)
#define pb push_back
#define re register
const double eps = 0.0000001;
using namespace std;
typedef pair pii;
inline int sgn(double x) {
    return (x > eps) - (x < -eps);
}
static char buf[100000],*pa=buf,*pd=buf;
#define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
    register LL x(0),f(1);register char c(gc);
    while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9')x=x*10+c-48,c=gc;
    return f*x;
}
const int N = 30010;
int T,n,m;char c;
int d[N],pre[N];
int Size[N];
int Find(int x)
{
    if(x == pre[x]) return x;
    int root = Find(pre[x]);//递归寻找树根
    d[x] += d[pre[x]];//维护d数组。——对边权求和
    return pre[x] = root;//路径压缩
}
void join(int x,int y)
{
    x = Find(x),y = Find(y);
    pre[x] = y;d[x] = Size[y];//合并后d[x] 应为 集合y的大小,因为是把x放到j后
    Size[y] += Size[x];//集合y的大小增加
}
void init()
{
    for(int i = 1;i<=N;++i) {
        pre[i] = i;
        Size[i] = 1;
    }
}
int main()
{
    init();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s%d%d",&c,&n,&m);
        if(c == 'M'){
            join(n,m);
        }
        else {
            if(Find(n)!=Find(m)){
                cout<<-1<

 

 

 

你可能感兴趣的:(图论算法—并查集)