首页 > 代码库 > 脑洞大开加偏执人格——可持久化treap版的Link Cut Tree

脑洞大开加偏执人格——可持久化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\n");
257             else
258                 printf("No\n");
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吧。。。