UVA 12538 Version Controlled IDE ( 持久化隨機二元搜尋樹 )
UVa Online Judge - Offline
Here are some good resources I read through in order to understand how to implement persistent RBST for this problem.
morris821028.github.io
blog.csdn.net
#include <bits/stdc++.h> using namespace std; const int MAXMEM = 5e7; const int MAXINT = ~( 1 << 31 ); const int MAXN = 5e4 + 4; const int MAXLEN = 1e6 + 5; struct rbst_node{ static rbst_node mem[MAXMEM]; char c; int size; rbst_node *lc, *rc; rbst_node(): lc(NULL), rc(NULL){} rbst_node(char _c): c(_c), size(1), lc(NULL), rc(NULL){} rbst_node(rbst_node *t){ c = t->c, size = t->size, lc = t->lc, rc = t->rc; } void pull(){ size = 1; if( lc ) size += lc->size; if( rc ) size += rc->size; } } rbst_node::mem[MAXMEM], *ptr = rbst_node::mem; int size(rbst_node *t){ return t ? t->size : 0; } void split(rbst_node *t, int k, rbst_node *&a, rbst_node *&b){ if( !t ) a = b = NULL; else{ if( k <= size( t->lc ) ){ b = new( ptr++ ) rbst_node( t ); split( t->lc, k, a, b->lc ); b->pull(); } else{ a = new( ptr++ ) rbst_node( t ); split( t->rc, k - size( t->lc ) - 1, a->rc, b ); a->pull(); } } } int rnd(){ static int rand_seed = 20160210; // QQ winter vacation's over return rand_seed = ( rand_seed * 0xdefaced + 1 ) & MAXINT; } rbst_node* merge(rbst_node *a, rbst_node *b){ if( !a || !b ) return a ? a : b; rbst_node *res; if( rnd() % ( a->size + b->size ) < a->size ){ res = new( ptr++ ) rbst_node( a ); res->rc = merge( res->rc, b ); } else{ res = new( ptr++ ) rbst_node( b ); res->lc = merge( a, res->lc ); } res->pull(); return res; } int d; // the variable that forced it to be online void print(rbst_node *t){ if( !t ) return; print( t->lc ); printf("%c", t->c); d += ( t->c == 'c' ); print( t->rc ); } int n; char str[MAXLEN]; int rcnt; rbst_node *root[MAXN]; int main(){ scanf("%d", &n); for(int i = 0; i < n; ++i){ rbst_node *tl, *tm, *tr; int op, v, p, c; scanf("%d", &op); if( op == 1 ){ root[ ++rcnt ] = root[ rcnt - 1 ]; scanf("%d%s", &p, str); p -= d; split( root[ rcnt ], p, tl, tr ); for(int j = 0; str[j]; ++j) tl = merge( tl, new( ptr++ ) rbst_node( str[j] ) ); root[ rcnt ] = merge( tl, tr ); } else if( op == 2 ){ root[ ++rcnt ] = root[ rcnt - 1 ]; scanf("%d%d", &p, &c); p -= d, c -= d; split( root[ rcnt ], p - 1, tl, tr ); split( tr, c, tm, tr ); root[ rcnt ] = merge( tl, tr ); } else{ scanf("%d%d%d", &v, &p, &c); v -= d, p -= d, c -= d; split( root[ v ], p - 1, tl, tr ); split( tr, c, tm, tr ); print( tm ); puts(""); } } return 0; }
As many people know, rope from c++ stl can work as an alternative. Here's link to the reference for rope:
https://www.sgi.com/tech/stl/Rope.html
though some in the network says it is a persistent block - linked list, in the reference I saw this "A character update requires time roughly logarithmic in the length of the string.", so I assume it is implemented upon a persistent BST. It works excellently when it comes to concatenating, inserting, and especially copying substrings. And BTW, it is named rope just to make some contrast with string, a little more heavy but mighty as well. *Note: I don't know why this doesn't work Hatena/uva12538_crope_wa.cpp at master · 1w0/Hatena · GitHub, maybe someday later I will find the reason.
#include <bits/stdc++.h> #include <ext/rope> using namespace std; using namespace __gnu_cxx; const int MAXN = 5e4 + 4; int n; int d; int vcnt; rope<char> t, ver[MAXN]; char str[MAXN]; int main(){ scanf("%d", &n); for(int i = 0; i < n; ++i){ int op, v, p, c; scanf("%d", &op); if( op == 1 ){ scanf("%d%s", &p, str); p -= d; t.insert( p, str ); ver[ ++vcnt ] = t; // ropes work in a persistent manner } else if( op == 2 ){ scanf("%d%d", &p, &c); p -= d, c -= d; t.erase( p - 1, c ); ver[ ++vcnt ] = t; } else{ scanf("%d%d%d", &v, &p, &c); p -= d, v -= d, c -= d; rope<char> ans = ver[ v ].substr( p - 1, c ); cout << ans << endl; d += count( ans.begin(), ans.end(), 'c' ); // iterator exists for rope } } return 0; }