【NOI2002】caioj1095: 并查集4(银河英雄传说)

来源:互联网 发布:室内分布设计软件 编辑:程序博客网 时间:2024/05/10 13:29

1095: 并查集4(银河英雄传说)

时间限制: 1 Sec 内存限制: 128 MB
题目描述
【问题描述】

公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展。
宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争。泰山压顶集团派宇宙舰队司令莱因哈特率领十万余艘战舰出征, 气吞山河集团点名将杨威利组织麾下三万艘战舰迎敌。
杨威利擅长排兵布阵,巧妙运用各种战术屡次以少胜多,难免恣生骄气。在这次决战中,他将巴米利恩星域战场划分成30000列,每列依次编号为1, 2, …, 30000。之后,他把自己的战舰也依次编号为1, 2, …, 30000,让第 i号战舰处于第 i列(i = 1, 2, …, 30000),形成“一字长蛇阵” ,诱敌深入。这是初始阵形。当进犯之敌到达时,杨威利会多次发布合并指令,将大部分战舰集中在某几列上,实施密集攻击。合并指令为M i j,含义为让第 i号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第 j号战舰所在的战舰队列的尾部。显然战舰队列是由处于同一列的一个或多个战舰组成的。 合并指令的执行结果会使队列增大。
然而,老谋深算的莱因哈特早已在战略上取得了主动。在交战中,他可以通过庞大的情报网络随时监听杨威利的舰队调动指令。
在杨威利发布指令调动舰队的同时, 莱因哈特为了及时了解当前杨威利的战舰分布情况,也会发出一些询问指令:C i j。该指令意思是,询问电脑,杨威利的第 i 号战舰与第 j 号战舰当前是否在同一列中,如果在同一列中,那么它们之间布置有多少战舰。
作为一个资深的高级程序设计员,你被要求编写程序分析杨威利的指令,以及回答莱因哈特的询问。
最终的决战已经展开,银河的历史又翻过了一页……
【输入文件】
输入文件galaxy.in的第一行有一个整数T(1<=T<=500,000) ,表示总共有T
条指令。
以下有T行,每行有一条指令。指令有两种格式:
1. M i j :i和 j是两个整数(1<=i , j<=30000) ,表示指令涉及的战舰编号。该指令是莱因哈特窃听到的杨威利发布的舰队调动指令,并且保证第 i号战舰与第 j号战舰不在同一列。
2. C i j :i和 j是两个整数(1<=i , j<=30000) ,表示指令涉及的战舰编号。该指令是莱因哈特发布的询问指令。
【输出文件】
输出文件为 galaxy.out。你的程序应当依次对输入的每一条指令进行分析和处理:
如果是杨威利发布的舰队调动指令,则表示舰队排列发生了变化,你的程序要注意到这一点,但是不要输出任何信息; 如果是莱因哈特发布的询问指令,你的程序要输出一行,仅包含一个整数,表示在同一列上,第 i 号战舰与第 j 号战舰之间布置的战舰数目。如果第 i 号战舰与第 j号战舰当前不在同一列上,则输出-1。
【样例输入】
4
M 2 3
C 1 2
M 2 4
C 4 2
【样例输出】
-1
1
样例说明
题目废话好多,,,关键可直接看样例说明即可

第一想法很简单,直接用并查集,求解数量就直接暴力求,测试一下过了样例,然而后面点计数却会超时,(500000操作。。。)显然要继续改进

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int fa[30001];int find(int x){    if (fa[x]!=x) {        fa[x]=find(fa[x]);     }    return fa[x];}int main(){    int t;    scanf("%d",&t);    for (int i=1;i<=30001;i++) fa[i]=i;    for (int i=1;i<=t;i++){        char p;int a,b;        cin>>p;        scanf("%d%d",&a,&b);        if (p=='M') {            fa[find(a)]=find(b);            fa[a]=find(b);        }           else{            if (fa[a]==fa[b]){                int s,minn,maxx;                minn=min(a,b)+1;                maxx=max(a,b);                for(int j=minn;j<=maxx;j++){                    if (fa[j]==fa[a]) s++;                }                 printf("%d\n",s);                s=0;            }            else{                printf("-1\n");            }        }    }    for (int i=1;i<=4;i++) printf("%d ",fa[i]);    return 0;}

出现问题之后我们就,现在一起想想想,(当你碰到困难 想!想!想!(雾
或者我们可以考虑利用一个数组来记录和维护一下数值是不是会方便一些呢?

这就好比是求两点之间的距离问题,多次寻求距离时我们很容易就想到前缀和,只要abs(队头-队尾)+1就可以求出距离

#include<bits/stdc++.h>using namespace std;int fa[30001],front[30001],num[30001],x,y,i,j,n,T,ans;    //fa[i]表示飞船i的祖先//front[i]表示飞船i与其所在列队头的距离                                        //num[i]表示第i列的飞船数量 char ins;int find(int n){                                        //查找祖先的函数     if(fa[n]==n)return fa[n];    int fn=find(fa[n]);                                    //先递归找到祖先     front[n]+=front[fa[n]];    //在回溯的时候更新front(因为更新时要用到正确的front[祖先],                                    //所以只能在回溯的时候更新)     return fa[n]=fn;}int main(){    cin>>T;    for(i=1;i<=30000;++i){                                //定初值         fa[i]=i;        front[i]=0;        num[i]=1;    }    while(T--){        cin>>ins>>x>>y;        int fx=find(x);                                    //fx为x所在列的队头         int fy=find(y);                                    //fy同上         if(ins=='M'){            front[fx]+=num[fy];        //更新front[x所在列队头(现在在y所在队列后面)]//即加上y所在队列的长度             fa[fx]=fy;                                    //将fy设为fx的祖先             num[fy]+=num[fx];                            //更新以fy为队头队列的长度             num[fx]=0;                        //以fx为队头的队列已不存在,更新         }        if(ins=='C'){            if(fx!=fy)cout<<"-1"<<endl;            //若x和y的祖先不相同,则不在同一列 else cout<<abs(front[x]-front[y])-1<<endl;    //否则利用x和y离队头的距离算//出它们的距离         }    }    return 0;}

from洛谷题解,,,侵删
回头再自己修改好

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 眼睛看手机久了模糊应怎么办 华为无线自拍杆连opp手机怎么办 苹果手机进水后自动跳电怎么办 魅族手机返回键不好使怎么办 手机壳是玻璃的摔坏了怎么办 魅族手机进水了开不了机怎么办 打发票机屏忘记了密码怎么办 魅族手机升级显示电量不足怎么办 魅蓝手机的图库没了怎么办 魅蓝5s屏幕碎了怎么办 魅族手机中间的home键失灵怎么办 魅族手机突然关机开不了机了怎么办 魅蓝3s卡顿怎么办视频 魅蓝3s手机太卡怎么办 红米4x外放破音怎么办 魅族手机刷机后内存变小了怎么办 手机用久了内存越来越小怎么办魅族 贴了车膜左右后视镜反光怎么办 贴手机膜时酒精没了怎么办 魅蓝e外屏幕碎了怎么办 贴的手机膜边缘翘起来着怎么办 手机后面贴的膜都是胶怎么办 车漆外面一层保护膜被划开了怎么办 美团骑手gps信号弱时怎么办 华为荣耀4x充电插口坏了怎么办 华为畅享5s开不了机怎么办 华为梅特10忘记账号密码怎么办 华为荣耀8充电接口坏了怎么办 华为手机锁屏了自动开屏怎么办 支付宝收货地址写错了怎么办 支付宝领海报地址写错了怎么办 手机总是弹出日历已停止运行怎么办 华为mate8忘了锁屏密码怎么办 红米4a打王者卡怎么办 苹果5s软件更新密码忘记了怎么办 华为荣耀P9进水了没有声音怎么办 华为荣耀7原相机不能拍照怎么办 华为手机触屏密码忘记了怎么办 华为荣耀10屏锁密码忘了怎么办 华为手机开机卡在开机界面怎么办 苹果6s国行不能用移动4g怎么办