• 银河英雄传说(边带权并查集)


    题目:

    有一个划分为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。

    数据范围

    N30000,T500000N≤30000,T≤500000

    输入样例:

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

    输出样例:

    -1
    1

    解题报告:边带权并查集的使用,咱们把每一列的战舰看成一个集合,用并查集维护,最初的时候,n个战舰就是n个独立的集合。
    在没有进行路径压缩的时候,far[x]就表示排在第x号战舰前边的那个战舰的编号,一个集合的代表就是位于最前边的战舰,另外,让树上的每条边带权值1,这样树上两点之间的距离减一就是两点之间间隔的战舰数目。
    在考虑路径压缩的情况下,咱们需要单独开设一个数组d,d[x]记录战舰x与far[x]之间的边的权值。在路径压缩把x连接到根节点的同时,把d[x]更新为从x到根节点的路径上的所有边权之和。
    下边的find函数增加了部分语句,实现了对d数组的维护:
     1 int find(int x)
     2 {
     3     if(far[x]==x)
     4     {
     5         return x;
     6     }
     7     int root=find(far[x]);
     8     data[x]+=data[far[x]];
     9     return far[x]=root;
    10 }

    当接受到一个C x y 指令时,分别执行find(x) ,find(y) 完成查询和路径压缩,若二者返回值相同,则说明在同一列,因为x,y这时都指向了根节点,所以d[x]存放了位于x之前的战舰数目,d[y]存放了位于y之前的战舰数目,二者之差的绝对值再减一,就是x,y之间间隔战舰的数目。

    当接受到一个M x y指令时,把x的根节点作为y的根节点的子结点,连接新边的权值应该设为合并之前集合y的大小,因此我们还需要一个size数组,在每个树根上记录集合的大小。

    merge函数:

    1 void merge(int x,int y)
    2 {
    3     x=find(x);
    4     y=find(y);
    5     far[x]=y;
    6     data[x]=size[y];
    7     size[y]+=size[x];
    8 }

    ac代码:

    //from:Onion
    //acwing 238 银河英雄传说 边带权并查集 
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    
    const int maxn=3e4+1000;
    int size[maxn],far[maxn],data[maxn];
    void init()
    {
    	for(int i=0;i<maxn;i++)
    	{
    		size[i]=1;
    		data[i]=0;
    		far[i]=i;
    	}
    }
    int find(int x)
    {
    	if(far[x]==x)
    	{
    		return x;
    	}
    	int root=find(far[x]);
    	data[x]+=data[far[x]];
    	return far[x]=root;
    }
    void merge(int x,int y)
    {
    	x=find(x);
    	y=find(y);
    	far[x]=y;
    	data[x]=size[y];
    	size[y]+=size[x];
    }
    int main()
    {
    	init();
    	int t;
    	scanf("%d",&t);
    	int x,y;
    	char cmd;
    	while(t--)
    	{
    		getchar();
    		scanf("%c%d%d",&cmd,&x,&y);
    		if(cmd=='M')
    		{
    			merge(x,y);
    		}
    		else
    		{
    			if(find(x)==find(y))
    			{
    				printf("%d
    ",abs(data[x]-data[y])-1);
    			}
    			else
    			{
    				printf("-1
    ");
    			}
    		}
    	}
    }
    

      

  • 相关阅读:
    java ssl https 连接详解 生成证书
    mysql实战优化之四:mysql索引优化
    mysql实战优化之五: 更新/插入优化 sql优化
    mysql实战优化之六:Order by优化 sql优化、索引优化
    mina2中IoHandler
    I/O通信模型(BIO,NIO,AIO)
    mina框架详解
    转:架构师于小波:魅族实时消息推送架构
    支付业务的数据库表的设计
    实战 TestNG 监听器
  • 原文地址:https://www.cnblogs.com/Spring-Onion/p/11327606.html
Copyright © 2020-2023  润新知