BZOJ2049: [Sdoi2008]Cave 洞穴勘测 Link-Cut-Tree 模板题
搞了这么长时间Splay终于可以搞LCT了,等等,什么是LCT?
$LCT$就是$Link-Cut-Tree$,是维护动态树的一个很高效的数据结构,每次修改和查询的均摊复杂度为$O(logN)$,因为那是用splay维护的,所以时间常数也会比较大..
但是相信有节操的出题人是不会恶意卡$LCT$的!
LCT的具体说明就就那篇喜闻乐见的Qtree研究,虽然我并没有怎么看懂,也许是我太弱了吧,总之和啃别人随手打的博客而言,那篇论文还是相对系统的了。
一句话概括$Link-Cut-Tree$就是Link-Cut-Tree=splay+树剖,所以下面的一些简要介绍沿用树剖和splay的用语。
具体说明几个操作;
0.$Splay$
和普通splay几乎一样,但是有一点需要注意,写在注释里了。
inline bool isroot(int node){
if(t[node].fa==0)return 1;
return t[t[node].fa].son[0]!=node&&t[t[node].fa].son[1]!=node;
}
inline int get(int node){return t[t[node].fa].son[1]==node;}
void rotate(int node){
int old=t[node].fa,oldf=t[old].fa,which=get(node);
if(!isroot(old))t[oldf].son[t[oldf].son[1]==old]=node;//先判断old是不是根再实现翻转,因为先翻转后无论如何old一定不是根
t[old].son[which]=t[node].son[which^1];t[t[old].son[which]].fa=old;
t[node].son[which^1]=old;t[old].fa=node;t[node].fa=oldf;
}
void splay(int x){
int top=0;q[++top]=x;
for(int i=x;!isroot(i);i=t[i].fa)q[++top]=t[i].fa;
for(int i=top;i;i--)downit(q[i]);
while(!isroot(x)){
int old=t[x].fa,oldf=t[old].fa;
if(!isroot(old))rotate(get(x)==get(old)?old:x);
rotate(x);
}
}
1.$Access$
这个操作就是把当前节点到当前树根变为重链。
具体实现的话和树剖其实有点像,跳到一条链的根,对链操作,跳掉下一条链的底。
void access(int node){
int tmp=0;
while(node){
splay(node);t[node].son[1]=tmp;
tmp=node;node=t[node].fa;
}
}
2.$Reverse$
具体的作用就是把一个节点转到根,和splay实现区间翻转挺像的,代码实现不难理解。
void Reverse(int node){access(node);splay(node);t[node].tag^=1;}
3.$Link$
首先把一个节点转到树根,然后由这个节点向另一节点连条虚边,然后splay一下。
void Link(int noda,int nodb){
Reverse(noda);
t[noda].fa=nodb;
splay(noda);
}
4.$Cut$
和上一个差不多。
void Cut(int noda,int nodb){Reverse(noda);access(nodb);splay(nodb);t[nodb].son[0]=t[noda].fa=0;}
5.$find$
int find(int node){
access(node);splay(node);
int tmp=node;
while(t[tmp].son[0])tmp=t[tmp].son[0];
return tmp;
}
6.$LCA$
void LCA(int noda,int nodb){//noda is LCA
Reverse(nodb);access(noda);splay(noda);
}
这些操作拼接起来就是这道题的实现了。
//BZOJ 2049
//by Cydiater
//2016.9.12
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <ctime>
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <algorithm>
using namespace std;
#define ll long long
#define up(i,j,n) for(int i=j;i<=n;i++)
#define down(i,j,n) for(int i=j;i>=n;i--)
#define FILE "sdoi2008_cave"
const int MAXN=1e6+5;
const int oo=0x3f3f3f3f;
inline int read(){
char ch=getchar();int x=0,f=1;
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int q[MAXN],top=0,head,tail,N,M,noda,nodb;
char s[15];
struct Splay{
int son[2],fa,tag,siz;
}t[MAXN];
namespace solution{
inline bool isroot(int node){
if(t[node].fa==0)return 1;
return t[t[node].fa].son[0]!=node&&t[t[node].fa].son[1]!=node;
}
inline int get(int node){return t[t[node].fa].son[1]==node;}
inline void downit(int node){
if(t[node].tag){
int leftson=t[node].son[0],rightson=t[node].son[1];
t[leftson].tag^=1;t[rightson].tag^=1;
swap(t[node].son[0],t[node].son[1]);
t[node].tag=0;
}
}
void rotate(int node){
int old=t[node].fa,oldf=t[old].fa,which=get(node);
if(!isroot(old))t[oldf].son[t[oldf].son[1]==old]=node;//先判断old是不是根再实现翻转,因为先翻转后无论如何old一定不是根
t[old].son[which]=t[node].son[which^1];t[t[old].son[which]].fa=old;
t[node].son[which^1]=old;t[old].fa=node;t[node].fa=oldf;
}
void splay(int x){
int top=0;q[++top]=x;
for(int i=x;!isroot(i);i=t[i].fa)q[++top]=t[i].fa;
for(int i=top;i;i--)downit(q[i]);
while(!isroot(x)){
int old=t[x].fa,oldf=t[old].fa;
if(!isroot(old))rotate(get(x)==get(old)?old:x);
rotate(x);
}
}
void access(int node){
int tmp=0;
while(node){
splay(node);t[node].son[1]=tmp;
tmp=node;node=t[node].fa;
}
}
void Reverse(int node){access(node);splay(node);t[node].tag^=1;}
void Link(int noda,int nodb){
Reverse(noda);
t[noda].fa=nodb;
splay(noda);
}
void Cut(int noda,int nodb){Reverse(noda);access(nodb);splay(nodb);t[nodb].son[0]=t[noda].fa=0;}
int find(int node){
access(node);splay(node);
int tmp=node;
while(t[tmp].son[0])tmp=t[tmp].son[0];
return tmp;
}
}
int main(){
//freopen(FILE".in","r",stdin);
//freopen(FILE".out","w",stdout);
freopen("input.in","r",stdin);
using namespace solution;
N=read();M=read();
while(M--){
scanf("%s",s);noda=read();nodb=read();
if(s[0]=='C')Link(noda,nodb);
if(s[0]=='D')Cut(noda,nodb);
if(s[0]=='Q')puts(find(noda)==find(nodb)?"Yes":"No");
}
return 0;
}
BZOJ2049: [Sdoi2008]Cave 洞穴勘测 Link-Cut-Tree 模板题的更多相关文章
- bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门
link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...
- BZOJ2049 SDOI2008 Cave 洞穴勘测 【LCT】
BZOJ2049 SDOI2008 Cave 洞穴勘测 Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分 ...
- 【LCT】BZOJ2049 [SDOI2008]Cave 洞穴勘测
2049: [Sdoi2008]Cave 洞穴勘测 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 10059 Solved: 4863[Submit ...
- [BZOJ2049][Sdoi2008]Cave 洞穴勘测 LCT模板
2049: [Sdoi2008]Cave 洞穴勘测 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 9705 Solved: 4674[Submit] ...
- [bzoj2049][Sdoi2008]Cave 洞穴勘测_LCT
Cave 洞穴勘测 bzoj-2049 Sdoi-2008 题目大意:维护一个数据结构,支持森林中加边,删边,求两点连通性.n个点,m个操作. 注释:$1\le n\le 10^4$,$1\le m\ ...
- [BZOJ2049] [SDOI2008] Cave 洞穴勘测 (LCT)
Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好 ...
- BZOJ2049——[Sdoi2008]Cave 洞穴勘测
1.题目大意:就是一个动态维护森林联通性的题 2.分析:lct模板题 #include <stack> #include <cstdio> #include <cstdl ...
- [bzoj2049][Sdoi2008]Cave 洞穴勘测——lct
Brief Description 给定一个森林,您需要支持两种操作: 链接两个节点. 断开两个节点之间的链接. Algorithm Design 对于树上的操作,我们现在已经有了树链剖分可以处理这些 ...
- bzoj2049: [Sdoi2008]Cave 洞穴勘测 lct裸题
题意:三种操作一种摧毁一条边,一种链接一条边,一种查询两个点是否联通 题解:lct的link和cut即可 /********************************************** ...
随机推荐
- ASP.NET 系列:单元测试之ConfigurationManager
通过ConfigurationManager使用.NET配置文件时,可以通过添加配置文件进行单元测试,虽然可以通过测试但达不到解耦的目的.使用IConfigurationManager和Configu ...
- FFmpeg 1.2 for Android 生成一个动态库
上一篇<FFmpeg 1.2 for Android 编译动态库>里沃特跟大家介绍了如何编译动态库,但当时所生成的动态库总共包含10个so文件,这样要是加载起来会严重影响软件的启动速度,后 ...
- js的bind方法
转载:http://www.jb51.net/article/94451.htm http://www.cnblogs.com/TiestoRay/p/3360378.html https://seg ...
- STM32 (战舰)
一.战舰STM32 1.引脚描述表---有ft 兼容5V 2.原理图----有ADC,不兼容5V 3.(1)学会基本外设:GPIO输入输出,外部中断,定时器,串口. (2)学会外设接口:SPI IIC ...
- 如何限制虚拟主机可使用的CPU资源
使用IIS 6.0运营虚拟主机的朋友们都会碰到这样一个问题,当某个网站占用大量CPU资源时,会把整个服务器都拖慢了,影响服务器上其他网站的访问速度,客户们的投诉也让系统管理员倍感头疼.我们知道,从II ...
- C++折半插入排序
代码如下: #include <iostream> using namespace std; void insertSort(int a[], int n) { for(int i=1;i ...
- [转]java.lang.OutOfMemoryError: PermGen space及其解决方法
原文地址:http://peak.iteye.com/blog/52606 这个问题是我的工程中加入了Birt报表在Linux环境下运行出现的问题,从网上搜索了一下看到这文章发现并不是由于Birt的原 ...
- php实现木桶排序
今天重新看了看木桶排序,思路比较简单,这里整理一下,免得下次忘记. 假设要对一组数据 2 2 3 1 6 5 4 进行桶排序. 1.首先选出最小元素1和最大元素6,做一个桶,也就是定义一个1-6的数组 ...
- 用cmd重命名.htaccess
本人上天修改PHP下伪静态文件htaccess.txt,需要改为.htaccess要是在Linux倒是很随意的事情,可惜window不给改,真的不可改吗,其实方法还是很多的,比如复制在记事本另存也可以 ...
- 使用kuernetes提供高可用的kibana服务
在kubernetes集群中部署kibana步骤如下: 1:kibana安装文件(目前最新版本4.5.1): 2:编写Dockerfile及执行点脚本文件run.sh,制作Kibana镜像: 3:推送 ...