首页 > 代码库 > 脑洞大开加偏执人格——可持久化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吧。。。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。