zoukankan      html  css  js  c++  java
  • 脑洞大开加偏执人格——可持久化treap版的Link Cut Tree

      一直没有点动态树这个科技树,因为听说只能用Splay,用Treap的话多一个log。有一天脑洞大开,想到也许Treap也能从底向上Split。仔细思考了一下,发现翻转标记不好写,再仔细思考了一下,发现还是可以写的,只需要实时交换答案二元组里的两棵树,最后在吧提出来的访问节点放回去就行了。本着只学一种平衡树的想法,脑洞大开加偏执人格的开始写可持久化Treap版的Link Cut Tree。。。

      写了才发现,常数硕大啊!!!代码超长啊!!!因为merge是从上到下,split从下到上,pushdown要写两个啊!!Link Cut Tree巧妙运用Splay特性将最左和最右提取之后合并是O(1)的呀!!Treap还要merge一次常数++啊。我冤枉啊!我只是不想学Splay啊!!好吧,我还是把它写出来了。。。

    题目:洞穴探测

    代码:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <algorithm>
      5 
      6 using namespace std;
      7 int father[10010];
      8 struct node
      9 {
     10     int num;
     11     int key;
     12     int left;
     13     int right;
     14     node* ls;
     15     node* rs;
     16     bool turn;
     17     node* f;
     18     node()
     19     {
     20         key=rand();
     21         f=NULL;
     22     }
     23 }no[10010];
     24 
     25 int root;
     26 
     27 void swap(node** a,node** b)
     28 {
     29     node* c=*a;
     30     *a=*b;
     31     *b=c;
     32 }
     33 
     34 void swap(int* a,int *b)
     35 {
     36     int c=*a;
     37     *a=*b;
     38     *b=c;
     39 }
     40 
     41 void pushdown(node* now)
     42 {
     43     if (now->turn)
     44     {
     45         swap(&now->ls,&now->rs);
     46         if (now->ls)
     47         {
     48             now->ls->turn=!now->ls->turn;    
     49             swap(&now->ls->left,&now->ls->right);
     50         }
     51         if (now->rs)
     52         {
     53             now->rs->turn=!now->rs->turn;
     54             swap(&now->rs->left,&now->rs->right);
     55         }
     56     }
     57     now->turn=false;
     58 }
     59 
     60 void update(node* now)
     61 {
     62     now->left=now->right=now->num;
     63     if (now->ls)
     64         now->left=now->ls->left;
     65     if (now->rs)
     66         now->right=now->rs->right;
     67 }
     68 
     69 node* merge(node* a,node* b)
     70 {
     71     if (!a) {update(b);return b;}
     72     if (!b) {update(a);return a;}
     73     pushdown(a);
     74     pushdown(b);
     75     if (a->key<b->key)
     76     {
     77         a->rs=merge(a->rs,b);
     78         a->rs->f=a;
     79         update(a);
     80         return a;
     81     }
     82     else
     83     {
     84         b->ls=merge(a,b->ls);
     85         b->ls->f=b;
     86         update(b);
     87         return b;
     88     }
     89 }
     90 
     91 struct nodepair 
     92 {
     93     node* l;
     94     node* r;
     95 
     96     nodepair(node* a,node* b)
     97     {
     98         l=a;
     99         r=b;
    100     }
    101 };
    102 
    103 nodepair pushdown(node* now,bool lr,nodepair ret)
    104 {
    105     now->turn=false;
    106     if (lr&&now->ls)
    107     {
    108         now->ls->turn=!now->ls->turn;
    109         swap(&now->ls->left,&now->ls->right);
    110     }
    111     if (!lr&&now->rs)
    112     {
    113         now->rs->turn=!now->rs->turn;
    114         swap(&now->rs->left,&now->rs->right);
    115     }
    116     swap(&now->ls,&now->rs);
    117     swap(&ret.l,&ret.r);
    118     if (ret.l)
    119     {
    120         ret.l->turn=!ret.l->turn;
    121         swap(&ret.l->left,&ret.l->right);
    122     }
    123     if (ret.r)    
    124     {
    125         ret.r->turn=!ret.r->turn;
    126         swap(&ret.r->left,&ret.r->right);
    127     }
    128     return ret;
    129 }
    130 nodepair split(node* start)
    131 {
    132     pushdown(start);
    133     node* cen=start;
    134     nodepair ret(start->ls,start->rs);
    135     if (start->ls)
    136         start->ls->f=NULL;
    137     if (start->rs)
    138         start->rs->f=NULL;
    139     start->ls=start->rs=NULL;
    140     bool lr;
    141     if (start->f)
    142         if (start->f->ls == start)
    143             lr=false;
    144         else
    145             lr=true;
    146     node* now=start->f;
    147     start->f=NULL;
    148     while (now)
    149     {
    150         if (now->turn)
    151         {
    152             ret=pushdown(now,lr,ret);
    153             lr=!lr;
    154         }
    155         node* next=now->f;
    156         now->f=NULL;
    157         if (lr)
    158         {
    159             now->rs=ret.l;
    160             if (ret.l)
    161                 ret.l->f=now;
    162             update(now);
    163             ret.l=now;
    164         }
    165         else
    166         {
    167             now->ls=ret.r;
    168             if (ret.r)
    169                 ret.r->f=now;
    170             update(now);
    171             ret.r=now;
    172         }
    173         if (next)
    174         {
    175             if (next->ls==now)
    176                 lr=false;
    177             else
    178                 lr=true;
    179         }
    180         now=next;
    181     }
    182     ret.l=merge(ret.l,cen);
    183     return ret;
    184 }
    185 
    186 node* access(int num)
    187 {
    188     int now=num;
    189     node* lasttree=NULL;
    190     while (now!=0)
    191     {
    192         nodepair km=split(&no[now]);
    193         if (lasttree)
    194             father[lasttree->left]=0;
    195         lasttree = merge(km.l,lasttree);
    196         if (km.r)    
    197             father[km.r->left]=now;
    198         now=father[lasttree->left];
    199     }
    200     return lasttree;
    201 }
    202 
    203 bool query(int x,int y)
    204 {
    205     int k1=access(x)->left;
    206     int k2=access(y)->left;
    207     return k1==k2;
    208 }
    209 
    210 void changeroot(int n)
    211 {
    212     node* road=access(n);
    213     road->turn=!road->turn;
    214     swap(&road->left,&road->right);
    215 }
    216 
    217 void Connect(int x,int y)
    218 {
    219     changeroot(y);
    220     access(x);
    221     father[y]=x;
    222 }
    223 
    224 void destroy(int x,int y)
    225 {
    226     changeroot(x);
    227     access(x);
    228     father[y]=0;
    229 }
    230 
    231 int main()
    232 {
    233     freopen("1839.in","r",stdin);
    234     freopen("1839.out","w",stdout);
    235     int n;
    236     cin>>n;
    237     for (int i=1;i<=n;++i)
    238     {
    239         no[i].num=i;
    240         father[i]=0;
    241     }
    242     int q;
    243     char cmd[10];
    244     scanf("%d",&q);
    245     for (int i=1;i<=q;++i)
    246     {
    247         int j,k;
    248         scanf("%s%d%d",cmd,&j,&k);
    249         if (cmd[0]=='C')
    250         {
    251             Connect(j,k);
    252         }
    253         if (cmd[0]=='Q')
    254         {
    255             if (query(j,k))
    256                 printf("Yes
    ");
    257             else
    258                 printf("No
    ");
    259         }
    260         if (cmd[0]=='D')
    261         {
    262             destroy(j,k);
    263         }
    264     }
    265     return 0;
    266 }

    2255ms 3769B

    一坨翔啊!!!!不过麻麻再也不用担心我写不来动态树了。。。

    准备过几天研究一下其他形式的可持久化TreapLCT,试着换种写法把常数降下来,代码量降下来。大概思想是先找到根,记录路径是走的左子树还是右子树,在走下来,感觉要好写很多。。。

    现在觉得Splay和Treap各有各的优点,Treap好理解,一般较快。Splay特性很神奇,可以干一些奇奇怪怪的事情。。。

    建议在我把常数降下来之前各位童鞋还是好好写Splay的LCT吧。。。

  • 相关阅读:
    gdb typeid 详解
    make报错
    期末作业验收
    个人作业——软件工程实践总结作业
    原型设计(结对第一次)
    团队展示(团队)
    第二次作业——个人项目实战(sudoku)
    软件工程实践第一次作业--准备
    C++第一次课堂作业 circle
    第四次作业 计算器第二部分(未完)
  • 原文地址:https://www.cnblogs.com/SymenYang/p/3721833.html
Copyright © 2011-2022 走看看