P2147 [SDOI2008] 洞穴勘测

P2147 [SDOI2008] 洞穴勘测

题目描述

辉辉热衷于洞穴勘测。

某天,他按照地图来到了一片被标记为JSZX的洞穴群地区。经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴。假如两个洞穴可以通过一条或者多条通道按一定顺序连接起来,那么这两个洞穴就是连通的,按顺序连接在一起的这些通道则被称之为这两个洞穴之间的一条路径。 洞穴都十分坚固无法破坏,然而通道不太稳定,时常因为外界影响而发生改变,比如,根据有关仪器的监测结果,123号洞穴和127号洞穴之间有时会出现一条通道,有时这条通道又会因为某种稀奇古怪的原因被毁。

辉辉有一台监测仪器可以实时将通道的每一次改变状况在辉辉手边的终端机上显示:

如果监测到洞穴u和洞穴v之间出现了一条通道,终端机上会显示一条指令 Connect u v

如果监测到洞穴u和洞穴v之间的通道被毁,终端机上会显示一条指令 Destroy u v

经过长期的艰苦卓绝的手工推算,辉辉发现一个奇怪的现象:无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径。

因而,辉辉坚信这是由于某种本质规律的支配导致的。因而,辉辉更加夜以继日地坚守在终端机之前,试图通过通道的改变情况来研究这条本质规律。 然而,终于有一天,辉辉在堆积成山的演算纸中崩溃了……他把终端机往地面一砸(终端机也足够坚固无法破坏),转而求助于你,说道:“你老兄把这程序写写吧”。

辉辉希望能随时通过终端机发出指令 Query u v,向监测仪询问此时洞穴u和洞穴v是否连通。现在你要为他编写程序回答每一次询问。 已知在第一条指令显示之前,JSZX洞穴群中没有任何通道存在。

数据范围:

100%的数据满足n≤10000, m≤200000

保证所有Destroy指令将摧毁的是一条存在的通道

本题输入、输出规模比较大,建议c\c++选手使用scanf和printf进行I\O操作以免超时


Solution:

非常简单的 LCT 练手题,它甚至保证所有操作合法(▰˘◡˘▰)。

我们直接打个LCT 板子上去就好了。

#include<bits/stdc++.h>
const int N=1e5+5;
using namespace std;
struct LCT{
struct Tree{
int ch[2],ff,val,sum,tag;
}t[N<<1];
#define ls t[x].ch[0]
#define rs t[x].ch[1]
#define fa t[x].ff
bool isnt_root(int x)
{
return (t[fa].ch[0]==x||t[fa].ch[1]==x);
}
void rev(int x)
{
swap(t[x].ch[0],t[x].ch[1]);
t[x].tag^=1;
}
inline void pushdown(int x)
{
if(!t[x].tag)return;
if(ls)rev(ls);
if(rs)rev(rs);
t[x].tag=0;
}
inline void pushup(int x)
{
t[x].sum=t[ls].sum+t[rs].sum+t[x].val;
}
void rotate(int x)
{
int y=fa,z=t[fa].ff,k=(t[fa].ch[1]==x);
if(isnt_root(y))t[z].ch[y==t[z].ch[1]]=x;
t[x].ff=z;
t[y].ch[k]=t[x].ch[!k];
if(t[x].ch[!k])t[t[x].ch[!k]].ff=y;
t[x].ch[!k]=y;
t[y].ff=x;
pushup(y);
}
int st[N];
void splay(int x)
{
int y=x,z=0;
st[++st[0]]=y;
while(isnt_root(y))st[++st[0]]=y=t[y].ff;
while(st[0])pushdown(st[st[0]--]);
while(isnt_root(x))
{
y=fa,z=t[fa].ff;
if(isnt_root(y))rotate((t[z].ch[1]==y)==(t[y].ch[1]==x) ? y : x);
rotate(x);
}
pushup(x);
}
void access(int x)
{
int y=0;
while(x)
{
splay(x);rs=y;pushup(x);
y=x;x=fa;
}
}
void make_root(int x)
{
access(x);splay(x);rev(x);
}
void splite(int x,int y)
{
make_root(x);access(y);splay(y);
}
int find(int x)
{
access(x);splay(x);
while(ls)pushdown(x),x=ls;
splay(x);
return x;
}
void link(int x,int y)
{
make_root(x);
if(find(y)!=x)t[x].ff=y;
}
void cut(int x,int y)
{
make_root(x);
if(find(y)==x&&t[y].ff==x&&!t[y].ch[0])
{
t[y].ff=t[x].ch[1]=0;
pushup(x);
}
}
bool check(int x,int y)
{
make_root(x);
return find(y)==x;
}
}T;
int n,m;
char c[10];
void work()
{
cin>>n>>m;
for(int i=1,x,y;i<=m;i++)
{
scanf("%s",c);
scanf("%d%d",&x,&y);
if(c[0]=='C')
{
T.link(x,y);
}
if(c[0]=='D')
{
T.cut(x,y);
}
if(c[0]=='Q')
{
printf(T.check(x,y) ? "Yes" : "No");putchar('\n');
}
}
}
int main()
{
//freopen("cave.in","r",stdin); freopen("cave.out","w",stdout);
work();
return 0;
}
posted @   liuboom  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示