博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj2049Cave 洞穴勘测
阅读量:4475 次
发布时间:2019-06-08

本文共 3367 字,大约阅读时间需要 11 分钟。

Description

辉辉热衷于洞穴勘测。某天,他按照地图来到了一片被标记为JSZX的洞穴群地区。经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴。假如两个洞穴可以通过一条或者多条通道按一定顺序连接起来,那么这两个洞穴就是连通的,按顺序连接在一起的这些通道则被称之为这两个洞穴之间的一条路径。洞穴都十分坚固无法破坏,然而通道不太稳定,时常因为外界影响而发生改变,比如,根据有关仪器的监测结果,123号洞穴和127号洞穴之间有时会出现一条通道,有时这条通道又会因为某种稀奇古怪的原因被毁。辉辉有一台监测仪器可以实时将通道的每一次改变状况在辉辉手边的终端机上显示:如果监测到洞穴u和洞穴v之间出现了一条通道,终端机上会显示一条指令 Connect u v 如果监测到洞穴u和洞穴v之间的通道被毁,终端机上会显示一条指令 Destroy u v 经过长期的艰苦卓绝的手工推算,辉辉发现一个奇怪的现象:无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径。因而,辉辉坚信这是由于某种本质规律的支配导致的。因而,辉辉更加夜以继日地坚守在终端机之前,试图通过通道的改变情况来研究这条本质规律。然而,终于有一天,辉辉在堆积成山的演算纸中崩溃了……他把终端机往地面一砸(终端机也足够坚固无法破坏),转而求助于你,说道:“你老兄把这程序写写吧”。辉辉希望能随时通过终端机发出指令 Query u v,向监测仪询问此时洞穴u和洞穴v是否连通。现在你要为他编写程序回答每一次询问。已知在第一条指令显示之前,JSZX洞穴群中没有任何通道存在。

Input

第一行为两个正整数n和m,分别表示洞穴的个数和终端机上出现过的指令的个数。以下m行,依次表示终端机上出现的各条指令。每行开头是一个表示指令种类的字符串s(”Connect”、”Destroy”或者”Query”,区分大小写),之后有两个整数u和v (1≤u, v≤n且u≠v) 分别表示两个洞穴的编号。

Output

对每个Query指令,输出洞穴u和洞穴v是否互相连通:是输出”Yes”,否则输出”No”。(不含双引号)

Sample Input

样例输入1 cave.in

200 5
Query 123 127
Connect 123 127
Query 123 127
Destroy 127 123
Query 123 127

样例输入2 cave.in

3 5
Connect 1 2
Connect 3 1
Query 2 3
Destroy 1 3
Query 2 3

Sample Output

样例输出1 cave.out

No
Yes
No

样例输出2 cave.out

Yes
No

“每条通道连接了恰好两个洞穴”,”无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径”

从这些信息里可以很容易的看出,洞穴和路径组成了一棵树或森林

好吧,这是lct的裸题(我竟然这么晚才学lct,退赛算了)

其实就是三个操作,
1.连边
2.拆边
3.查询两个点是不是联通

前两个操作都太显然了

然而第三个怎么办呢,啊啊啊啊啊(本蒟蒻就懵b了)
好吧,我们仔细考虑一下(如图)
这里写图片描述

在写lct时有一个需要特别注意的点(第一次写,调了好久,感谢曲神)

这里写图片描述

这里写代码片#include
#include
#include
using namespace std;const int N=10010;int n,m,ch[N][2],pre[N],q[N];bool rev[N]; int get(int bh){ return (ch[pre[bh]][0]==bh ? 0:1);}void push(int bh){ if (rev[bh]) { rev[bh]^=1; rev[ch[bh][0]]^=1; rev[ch[bh][1]]^=1; swap(ch[bh][0],ch[bh][1]); }}bool isroot(int bh){ return ch[pre[bh]][1]!=bh&&ch[pre[bh]][0]!=bh;}void rotate(int bh) { int fa=pre[bh]; int grand=pre[fa]; int wh=get(bh); if (!isroot(fa)) ch[grand][ch[grand][0]==fa ? 0:1]=bh; // ch[fa][wh]=ch[bh][wh^1]; pre[ch[fa][wh]]=fa; ch[bh][wh^1]=fa; pre[fa]=bh; pre[bh]=grand; return;}void splay(int bh){ int top=0; q[++top]=bh; for (int i=bh;!isroot(i);i=pre[i]) //!isroot(i);i=pre[i] q[++top]=pre[i]; while (top) push(q[top--]); for (int fa;!isroot(bh);rotate(bh)) if (!isroot(fa=pre[bh])) rotate(get(fa)==get(bh) ? fa:bh); return;}void expose(int bh) //查询x { int t=0; while (bh) { splay(bh); ch[bh][1]=t; // t=bh; bh=pre[bh]; }}void makeroot(int bh) //翻转操作 { expose(bh); splay(bh); rev[bh]^=1;}void link(int x,int y){ makeroot(x); pre[x]=y; // splay(x);}void cut(int x,int y){ makeroot(x); expose(y); splay(y); ch[y][0]=pre[x]=0; //ch[y][0]=pre[x]}int find(int bh) //寻找x所在的辅助树中对应的原树的根(深度最小){ expose(bh); splay(bh); int t=bh; while (ch[t][0]) t=ch[t][0]; return t;}int main(){ scanf("%d%d",&n,&m); char opt[10]; scanf("%c",&opt[0]); for (int i=1;i<=m;i++) { int x,y; scanf("%s",&opt); scanf("%d%d",&x,&y); if (opt[0]=='C') link(x,y); else if (opt[0]=='D') cut(x,y); else{ if (find(x)==find(y)) printf("Yes\n"); else printf("No\n"); } scanf("%c",&opt[0]); } return 0;}

转载于:https://www.cnblogs.com/wutongtong3117/p/7673561.html

你可能感兴趣的文章
当使用Switch时 case太多,用委托代替
查看>>
ROS探索总结(三)——ROS新手教程
查看>>
Linux GCC常用命令
查看>>
冒泡排序
查看>>
工作心得1
查看>>
6-Ubuntu—截屏与截取选定区域
查看>>
树链剖分
查看>>
代码演示 Linq 延迟执行(Deferred Execution) 带来的问题
查看>>
内网安全体系建设工作思路
查看>>
第16月第25天 tableView设置UITableViewStyleGrouped顶部有空余高度
查看>>
RPC服务的发布订阅实现(基于Zookeeper服务) 转载
查看>>
读取配置文件包含properties和xml文件
查看>>
解决Mac安装tesserocr报错问题 Failed building wheel for
查看>>
adplus 抓取dump
查看>>
Github 开源:使用 .NET WinForm 开发所见即所得的 IDE 开发环境(Sheng.Winform.IDE)【2.源代码简要说明】...
查看>>
[学习笔记]关于CUDA与OPENCL
查看>>
kafka之consumer参数auto.offset.reset 0.10+
查看>>
Strategic Game HDU - 1054(最小顶点覆盖)
查看>>
C#删除程序自身【总结】
查看>>
单例和多线程
查看>>