zoukankan      html  css  js  c++  java
  • 【BZOJ2049】洞穴勘测(SDOI2008)-LCT真·模板题

    测试地址:洞穴勘测

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

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

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

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    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
    ");
    	  else printf("No
    ");
    	}
    	if (op[0]=='C') link(x,y);
    	if (op[0]=='D') cut(x,y);
      }
      
      return 0;
    }
    


  • 相关阅读:
    c语言 数组名是常量指针
    c语言 动态数组
    c语言 指针的值
    c语言 &取地址运算符的理解
    c语言 指针与地址的区别
    c语言 指针与数组
    linux cheese摄像机工具在window电脑上显示
    C#实现简单的 Ping 的功能,用于测试网络是否已经联通
    c# 扫描局域网IP列表的几种方法
    c# 遍历局域网计算机(电脑)获取IP和计算机名称
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793724.html
Copyright © 2011-2022 走看看