【BZOJ2049】洞穴勘测(SDOI2008)-LCT真·模板题

测试地址:洞穴勘测

做法:听说这题可以用并查集水过......为了训练LCT还是不要做这种事了吧......

根据题目描述,图无论怎么变化都是一个森林,那么我们就要用到LCT最经典的用法了:维护森林的连通性。然后link和cut就是模板了,检测两个点之间的连通性的话,我们只需要检查这两个点在不在同一棵树上(真的树,不是splay)即可。至于模板我是向kuangbin神犇学的,既快,写着也舒服。

犯二的地方:splay的时候把跳出循环的条件写成!pre[x]了,导致TLE到死......一定要记住pre[x]为0的时候表示x为真树的根,rt[x]为1的时候才表示x为它所在的splay中的根。

以下是本人代码:

#include 
#include 
#include 
#include 
#include 
using namespace std;
int n,m,ch[10010][2]={0},pre[10010]={0};
bool rev[10010]={0},rt[10010]={0};

void reverse(int x)
{
  rev[x]^=1;
  swap(ch[x][0],ch[x][1]);
}

void pushdown(int x)
{
  if (rev[x])
  {
    reverse(ch[x][0]);
	reverse(ch[x][1]);
	rev[x]=0;
  }
}

void pushup(int x)
{
  
}

void rotate(int x,bool f)
{
  int y=pre[x];
  ch[y][!f]=ch[x][f];
  pre[ch[x][f]]=y;
  ch[x][f]=y;
  if (!rt[y]) ch[pre[y]][ch[pre[y]][1]==y]=x;
  else rt[y]=0,rt[x]=1;
  pre[x]=pre[y];pre[y]=x;
  pushup(y);
}

void Push(int x)
{
  if (!rt[x]) Push(pre[x]);
  pushdown(x);
}

void Splay(int x)
{
  Push(x);
  while(!rt[x])
  {
    if (rt[pre[x]]) rotate(x,ch[pre[x]][0]==x);
	else
	{
	  int y=pre[x],z=pre[pre[x]];
	  bool f=(ch[z][1]==y);
	  if (ch[y][f]==x) rotate(y,!f),rotate(x,!f);
	  else rotate(x,f),rotate(x,!f);
	}
  }
  pushup(x);
}

void access(int x)
{
  int y=0;
  do
  {
    Splay(x);
	rt[ch[x][1]]=1,rt[ch[x][1]=y]=0;
	pushup(x);
	x=pre[y=x];
  }while(x);
}

int find_root(int x)
{
  while(pre[x]) x=pre[x];
  return x;
}

void move(int x)
{
  access(x);
  Splay(x);
  reverse(x);
}

void cut(int x,int y)
{
  move(x);
  Splay(y);
  pre[ch[y][0]]=pre[y];
  pre[y]=0;
  rt[ch[y][0]]=1;
  ch[y][0]=0;
  pushup(y);
}

void link(int x,int y)
{
  move(x);
  pre[x]=y;
}

int main()
{
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) rt[i]=1;
  
  for(int i=1;i<=m;i++)
  {
    char op[30];
	int x,y;
    scanf("%s%d%d",op,&x,&y);
	if (op[0]=='Q')
	{
	  if (find_root(x)==find_root(y)) printf("Yes\n");
	  else printf("No\n");
	}
	if (op[0]=='C') link(x,y);
	if (op[0]=='D') cut(x,y);
  }
  
  return 0;
}


你可能感兴趣的:(数据结构-平衡树/set,数据结构-LCT)