zoukankan      html  css  js  c++  java
  • [SDOI2008] 洞穴勘测 (LCT模板)

    bzoj 2049 传送门

    洛谷P2147 传送门

    这个大佬的LCT详解超级棒的!

    Link-Cut Tree的基本思路是用splay的森林维护一条条树链。

    splay的森林,顾名思义,就是若干splay组成的东西。

    每个splay都有一个根节点,所以lct里的splay不能记录根节点,因为根节点有好多。

    我们开一个bool数组记录每个点是否为根节点。

    每个splay都维护一条重链,重链之间的轻链在splay里只从儿子指向父亲,而父亲并没有这个儿子。

    就像图里的红箭头。

    每个splay都表示一条重链,这个splay的中序遍历与链上节点的深度顺序是一致的。

    接下来是splay里最重要的操作:access(p)

    就是指打通从p到整棵树的树根的一条重链。

    同时也把p下面接的链变成轻链。

    之后还有一个操作:move_to_root,把p变成整棵树的根。

    在access之后,p和树根之间是重链直接连接,而一个splay维护一个重链,所以此时p和根已经在一个splay里了。

    我们只需要splay(p)即可。

    但是这样的话破坏了深度的性质。

    把左右反转一下就行了:reverse(p)

    接下来就是link和cut的操作。

    link(x,y)很简单,mtr(x),之后接一条从x到y的轻链即可。

    cut(x,y)的话,mtr(x),access(y),splay(y),x就是y的左儿子了。删掉父子关系即可。

    查询连通性:mtr(x),access(y),splay(y),x就在y的子树里了。x=f[x]一直往上跳,判断最后y的终点是不是x。

    这些大概是最最基础的操作了,子树信息什么的都不用维护。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #define id(x) (s[f[x]][1]==x)
      5 using namespace std;
      6 
      7 int n,m;
      8 int f[10005],s[10005][2];
      9 bool rev[10005],rt[10005];
     10 
     11 void reverse(int p)
     12 {
     13     swap(s[p][0],s[p][1]);
     14     rev[p]^=1;
     15 }
     16 
     17 void pushdown(int p)
     18 {
     19     if(!rev[p])return;
     20     reverse(s[p][0]);
     21     reverse(s[p][1]);
     22     rev[p]=0;
     23 }
     24 
     25 void down(int p)
     26 {
     27     if(!rt[p])down(f[p]);
     28     pushdown(p);
     29 }
     30 
     31 void rotate(int p)
     32 {
     33     int k=id(p);
     34     int fa=f[p];
     35     if(rt[fa])rt[p]=1,rt[fa]=0;
     36     else s[f[fa]][id(fa)]=p;
     37     s[fa][k]=s[p][!k];
     38     s[p][!k]=fa;
     39     f[p]=f[fa];
     40     f[fa]=p;
     41     f[s[fa][k]]=fa;
     42 }
     43 
     44 void splay(int p)
     45 {
     46     down(p);
     47     while(!rt[p])
     48     {
     49         int fa=f[p];
     50         if(rt[fa])
     51         {
     52             rotate(p);
     53             return;
     54         }
     55         if(id(p)^id(fa))rotate(p);
     56         else rotate(fa);
     57         rotate(p);
     58     }
     59 }
     60 
     61 void access(int p)
     62 {
     63     int son=0;
     64     while(p)
     65     {
     66         splay(p);
     67         rt[s[p][1]]=1,rt[son]=0;
     68         s[p][1]=son;
     69         son=p,p=f[p];
     70     }
     71 }
     72 
     73 void mtr(int p)
     74 {
     75     access(p);
     76     splay(p);
     77     reverse(p);
     78 }
     79 
     80 void link(int x,int y)
     81 {
     82     mtr(x);
     83     f[x]=y;
     84 }
     85 
     86 void cut(int x,int y)
     87 {
     88     mtr(x);
     89     access(y);
     90     splay(y);
     91     s[y][0]=f[x]=0;
     92     rt[x]=1;
     93 }
     94 
     95 void check(int x,int y)
     96 {
     97     mtr(x);
     98     access(y);
     99     splay(y);
    100     while(!rt[x])x=f[x];
    101     printf("%s
    ",(x==y?"Yes":"No"));
    102 }
    103 
    104 int main()
    105 {
    106     scanf("%d%d",&n,&m);
    107     for(int i=1;i<=n;i++)rt[i]=1;
    108     char op[15];
    109     int x,y;
    110     while(m--)
    111     {
    112         scanf("%s",op+1);
    113         scanf("%d%d",&x,&y);
    114         if(op[1]=='C')link(x,y);
    115         if(op[1]=='D')cut(x,y);
    116         if(op[1]=='Q')check(x,y);
    117     }
    118     return 0;
    119 }
  • 相关阅读:
    动态规划-树形dp
    排队打水
    耍杂技的牛
    合并果子
    贪心问题-区间类
    动态规划-状态压缩dp
    Linux分区知识及企业场景分区76
    企业面试题-find结合sed查找替换
    企业面试题-利用三剑客
    alias-unalias
  • 原文地址:https://www.cnblogs.com/eternhope/p/9648995.html
Copyright © 2011-2022 走看看