可持久化应该都知道…
就是可以回退历史版本…以及区间查询一些东西比如说k值…(不过k值还不是主要用处?)
可持久化略解:
就是复制其他的根节点 按照过去版本添加当前版本新建节点…和之前是独立的
但是是共用节点…从而使内存减少了很多…
按照以前的版本新建节点到当前的版本…复制版本就是直接复制根节点
rt[i]=rt[pre];
可持久化线段树
求静态区间k大…
就是弄个前缀和的东西 l~mid mid+1~r的这段值域中二分没了…
#include <cstdio> #include <algorithm> using ll = long long ; using namespace std ; int read() { int x = 0 , f = 1 ; char c = getchar() ; while(c < '0' || c > '9') { if(c == '-') f = -1 ; c = getchar() ; } while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c & 15) ; c = getchar() ; } return x * f ; } template < class T > void print(T x , char c = '\n') { static char _st[100] ; int _stp = 0 ; if(x == 0) { putchar('0') ; } if(x < 0) { putchar('-') ; x = -x ; } while(x) { _st[++ _stp] = (x % 10) ^ 48 ; x /= 10 ; } while(_stp) { putchar(_st[_stp --]) ; } putchar(c) ; } const int N = 2e5 + 10; int n , m , a[N] , b[N] , rt[N] , ls[N << 5] , rs[N << 5] , sum[N << 5] , cnt = 0 ; void upd(int pre , int & p , int l , int r , int val) { ls[p = ++ cnt] = ls[pre] ; rs[p] = rs[pre] ; sum[p] = sum[pre] + 1 ; if(l == r) { return ; } int mid = l + r >> 1 ; if(val <= mid) { upd(ls[pre] , ls[p] , l , mid , val) ; } else { upd(rs[pre] , rs[p] , mid + 1 , r , val) ; } } int query(int L , int R , int l , int r , int k) { if(l == r) { return l ; } int mid = l + r >> 1 , val = sum[ls[R]] - sum[ls[L]] ; if(val >= k) { return query(ls[L] , ls[R] , l , mid , k) ; } else { return query(rs[L] , rs[R] , mid + 1 , r , k - val) ; } } int main() { n = read() ; m = read() ; for(int i = 1 ; i <= n ; i ++) { a[i] = read() ; b[i] = a[i] ; } sort(b + 1 , b + n + 1) ; int len = unique(b + 1 , b + n + 1) - b - 1 ; for(int i = 1 ; i <= n ; i ++) { a[i] = lower_bound(b + 1 , b + len + 1 , a[i]) - b ; } for(int i = 1 ; i <= n ; i ++) { upd(rt[i - 1] , rt[i] , 1 , n , a[i]) ; } for(int i = 1 ; i <= m ; i ++) { int l = read() , r = read() , k = read() ; print(b[query(rt[-- l] , rt[r] , 1 , n , k)]) ; } return 0 ; }
可持久化并查集
像是启发式合并一样 深度浅的弄到深度深的…
#include <cstdio> using ll = long long ; using namespace std ; int read() { int x = 0 , f = 1 ; char c = getchar() ; while(c < '0' || c > '9') { if(c == '-') f = -1 ; c = getchar() ; } while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c & 15) ; c = getchar() ; } return x * f ; } template < class T > void print(T x , char c = '\n') { static char _st[100] ; int _stp = 0 ; if(x == 0) { putchar('0') ; } if(x < 0) { putchar('-') ; x = -x ; } while(x) { _st[++ _stp] = (x % 10) ^ 48 ; x /= 10 ; } while(_stp) { putchar(_st[_stp --]) ; } putchar(c) ; } const int N = 2e5 + 10 ; int n , m , fa[N << 5] , dep[N << 5] ; int ls[N << 5] , rs[N << 5] , rt[N] , cnt = 0 ; void swap(int & x , int & y) { x ^= y ^= x ^= y ; } void build(int & p , int l , int r) { p = ++ cnt ; if(l == r) { fa[p] = l ; return ; } int mid = l + r >> 1 ; build(ls[p] , l , mid) ; build(rs[p] , mid + 1 , r) ; } void upd(int pre , int & p , int l , int r , int pos , int f) { p = ++ cnt ; ls[p] = ls[pre] ; rs[p] = rs[pre] ; if(l == r) { fa[p] = f ; dep[p] = dep[pre] ; return ; } int mid = l + r >> 1 ; if(pos <= mid) upd(ls[pre] , ls[p] , l , mid , pos , f) ; else upd(rs[pre] , rs[p] , mid + 1 , r , pos , f) ; } int query(int p , int l , int r , int pos) { if(l == r) { return p ; } int mid = l + r >> 1 ; if(pos <= mid) return query(ls[p] , l , mid , pos) ; else return query(rs[p] , mid + 1 , r , pos) ; } void add(int p , int l , int r , int pos) { if(l == r) { dep[p] ++ ; return ; } int mid = l + r >> 1; if(pos <= mid) add(ls[p] , l , mid , pos) ; else add(rs[p] , mid + 1 , r , pos) ; } int find(int p , int x) { int f = query(p , 1 , n , x) ; if(x == fa[f]) { return f ; } return find(p , fa[f]) ; } int main() { n = read() ; m = read() ; build(rt[0] , 1 , n) ; for(int i = 1 ; i <= m ; i ++) { int opt = read() ; if(opt == 1) { rt[i] = rt[i - 1] ; int a = read() , b = read() ; int f1 = find(rt[i] , a) , f2 = find(rt[i] , b) ; if(fa[f1] == fa[f2]) { continue ; } if(dep[f1] > dep[f2]) { swap(f1 , f2) ; } upd(rt[i - 1] , rt[i] , 1 , n , fa[f1] , fa[f2]) ; if(dep[f1] == dep[f2]) { add(rt[i] , 1 , n , fa[f2]) ; } } if(opt == 2) rt[i] = rt[read()] ; if(opt == 3) { rt[i] = rt[i - 1] ; int a = read() , b = read() ; int f1 = find(rt[i] , a) , f2 = find(rt[i] , b) ; print(fa[f1] == fa[f2]) ; } } return 0 ; }
可持久化数组…
带修…回退查询
用可持久化线段树搞搞就好了…
// luogu-judger-enable-o2 //Isaunoya #include<bits/stdc++.h> using namespace std ; inline int read() { register int x = 0 ; register int f = 1 ; register char c = getchar() ; for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ; for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ; return x * f ; } int st[105] ; template < typename T > inline void write(T x , char c = '\n') { int tp = 0 ; if(x == 0) return (void) puts("0") ; if(x < 0) putchar('-') , x = -x ; for( ; x ; x /= 10) st[++ tp] = x % 10 ; for( ; tp ; tp --) putchar(st[tp] + '0') ; putchar(c) ; } //#define Online_Judge const int N = 1000000 + 5 ; int n , q , a[N] , rt[N<<5] ; struct node { int lc[N<<5] , rc[N<<5] , val[N<<5] , cnt = 0 ; inline void build(int l , int r , int &p) { p = ++ cnt ; if(l == r) { val[p] = a[l] ; return ; } int mid = l + r >> 1 ; build(l , mid , lc[p]) ; build(mid + 1 , r , rc[p]) ; } inline void Insert(int pre , int l , int r , int pos , int v , int & p) { p = ++ cnt ; lc[p]=lc[pre]; rc[p]=rc[pre]; val[p]=val[pre]; if(l == r) { val[p] = v ; return ; } int mid = l + r >> 1 ; if(pos<=mid) Insert(lc[pre] , l , mid , pos , v , lc[p]) ; else Insert(rc[pre] , mid + 1 , r , pos , v , rc[p]) ; } inline int Query(int l , int r , int p , int pos) { if(l == r) return val[p] ; int mid = l + r >> 1 ; if(pos <= mid) return Query(l , mid , lc[p] , pos) ; else return Query(mid + 1 , r , rc[p] , pos) ; } }T ; signed main() { #ifdef Online_Judge freopen("testdata.in" , "r" , stdin) ; freopen("testdata2.out" , "w" , stdout) ; #endif n = read() ; q = read() ; for(register int i = 1 ; i <= n ; i ++) a[i] = read() ; T.build(1,n,rt[0]) ; for(register int i = 1 ; i <= q ; i ++) { int pre (read()) ; int opt (read()) ; int x (read()) ; if(opt == 1) { int v = read() ; T.Insert(rt[pre] , 1 , n , x , v , rt[i]) ; } else { printf("%d\n" , T.Query(1 , n , rt[pre] , x)) ; rt[i]=rt[pre] ; } } return 0 ; }
可持久化平衡树
平衡树的加强版(?)
但不能splay了…然后硬着头皮去学了fhq treap(fhq真香)
#include <cstdio> #include <bits/stdc++.h> using ll = long long ; using namespace std ; int read() { int x = 0 , f = 1 ; char c = getchar() ; while(c < '0' || c > '9') { if(c == '-') f = -1 ; c = getchar() ; } while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c & 15) ; c = getchar() ; } return x * f ; } template < class T > void print(T x , char c = '\n') { static char _st[100] ; int _stp = 0 ; if(x == 0) { putchar('0') ; } if(x < 0) { putchar('-') ; x = -x ; } while(x) { _st[++ _stp] = (x % 10) ^ 48 ; x /= 10 ; } while(_stp) { putchar(_st[_stp --]) ; } putchar(c) ; } const int N = 1e6 + 10 ; struct Node { int val , sz , rnd , ch[2] ; } tr[N * 80] ; int n , cnt = 0 , rt[N] ; #define ls(x) tr[x].ch[0] #define rs(x) tr[x].ch[1] void pushup(int x) { tr[x].sz = tr[ls(x)].sz + tr[rs(x)].sz + 1 ; } int merge(int u , int v) { if(! u || ! v) return u | v ; int p = ++ cnt ; if(tr[u].rnd < tr[v].rnd) { tr[p] = tr[u] ; rs(p) = merge(rs(p) , v) ; pushup(p) ; return p ; } else { tr[p] = tr[v] ; ls(p) = merge(u , ls(p)) ; pushup(p) ; return p ; } } void split(int x , int k , int & u , int & v) { if(! x) { u = v = 0 ; return ; } if(k >= tr[x].val) { tr[u = ++ cnt] = tr[x] ; split(rs(u) , k , rs(u) , v) ; pushup(u) ; } else { tr[v = ++ cnt] = tr[x] ; split(ls(v) , k , u , ls(v)) ; pushup(v) ; } } int main() { auto insert = [&] (int & rt , int val) { auto Newnode = [&] (int val){ tr[++ cnt] = { val , 1 , rand() } ; return cnt ; } ; int x, y ; split(rt , val , x , y) ; rt = merge(merge(x , Newnode(val)) , y) ; } ; auto remove = [&] (int & rt , int val) { int x , y , z ; split(rt , val , x , z) ; split(x , val - 1 , x , y) ; rt = merge(merge(x , merge(ls(y) , rs(y))) , z) ; } ; auto rank = [&] (int & rt , int val) { int x , y ; split(rt , val - 1 , x , y) ; int ans = tr[x].sz + 1 ; rt = merge(x , y) ; return ans ; } ; auto kth = [&] (int rt , int k) { while(rt) { int sum = tr[ls(rt)].sz + 1 ; if(sum == k) { return tr[rt].val ; } if(sum > k) { rt = ls(rt) ; } else { k -= sum ; rt = rs(rt) ; } } } ; auto pre = [&] (int rt , int v) { int ans = -2147483647 ; while(rt) { if(tr[rt].val < v) { ans = tr[rt].val ; rt = rs(rt) ; } else { rt = ls(rt) ; } } return ans ; } ; auto nxt = [&] (int rt , int v) { int ans = 2147483647 ; while(rt) { if(tr[rt].val > v) { ans = tr[rt].val ; rt = ls(rt) ; } else { rt = rs(rt) ; } } return ans ; } ; n = read() ; for(int i = 1 ; i <= n ; i ++) { int ver = read() , opt = read() , x = read() ; rt[i] = rt[ver] ; if(opt == 1) insert(rt[i] , x) ; if(opt == 2) remove(rt[i] , x) ; if(opt == 3) print(rank(rt[i] , x)) ; if(opt == 4) print(kth(rt[i] , x)) ; if(opt == 5) print(pre(rt[i] , x)) ; if(opt == 6) print(nxt(rt[i] , x)) ; } return 0 ; }
可持久化文艺平衡树
区间翻转…回退历史版本
还是可持久化平衡树… 支持插入…
#include <cstdio> #include <bits/stdc++.h> using ll = long long ; using namespace std ; int read() { int x = 0 , f = 1 ; char c = getchar() ; while(c < '0' || c > '9') { if(c == '-') f = -1 ; c = getchar() ; } while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c & 15) ; c = getchar() ; } return x * f ; } template < class T > void print(T x , char c = '\n') { static char _st[100] ; int _stp = 0 ; if(x == 0) { putchar('0') ; } if(x < 0) { putchar('-') ; x = -x ; } while(x) { _st[++ _stp] = (x % 10) ^ 48 ; x /= 10 ; } while(_stp) { putchar(_st[_stp --]) ; } putchar(c) ; } int n ; ll lastans = 0 ; const int N = 2e5 + 10 ; int rt[N] ; struct Node { int ls , rs , val , rnd , sz ; ll sum ; bool rev ; } tr[N * 80] ; #define ls(x) tr[x].ls #define rs(x) tr[x].rs int cnt = 0 ; void pushup(int x) { tr[x].sz = tr[ls(x)].sz + tr[rs(x)].sz + 1 ; tr[x].sum = tr[ls(x)].sum + tr[rs(x)].sum + tr[x].val ; } void pushdown(int x) { if(! tr[x].rev) return ; if(ls(x)) { int tmp = ls(x) ; tr[tr[x].ls = ++ cnt] = tr[tmp] ; tr[ls(x)].rev = tr[tmp].rev ^ 1 ; } if(rs(x)) { int tmp = rs(x) ; tr[tr[x].rs = ++ cnt] = tr[tmp] ; tr[rs(x)].rev = tr[tmp].rev ^ 1 ; } swap(tr[x].ls , tr[x].rs) ; tr[x].rev = 0 ; } int NewNode(int v) { tr[++ cnt] = { 0 , 0 , v , rand() , 1 , v , 0 } ; return cnt ; } int Merge(int u , int v) { if(! u || ! v) return u | v ; if(tr[u].rnd < tr[v].rnd) { pushdown(u) ; rs(u) = Merge(rs(u) , v) ; pushup(u) ; return u ; } pushdown(v) ; ls(v) = Merge(u , ls(v)) ; pushup(v) ; return v ; } void Split(int cur , int k , int & u , int & v) { if(! cur) { u = v = 0 ; return ; } pushdown(cur) ; if(k > tr[ls(cur)].sz) { tr[u = ++ cnt] = tr[cur] ; Split(rs(cur) , k - tr[ls(cur)].sz - 1 , rs(u) , v) ; pushup(u) ; } else { tr[v = ++ cnt] = tr[cur] ; Split(ls(cur) , k , u , ls(v)) ; pushup(v) ; } } void Insert(int & rt , int p , int val) { int x , y ; Split(rt , p , x , y) ; rt = Merge(Merge(x , NewNode(val)) , y) ; } void Remove(int & rt , int p) { int x , y , z ; Split(rt , p , x , z) ; Split(x , p - 1 , x , y) ; rt = Merge(x , z) ; } void Reverse(int & rt , int l , int r) { int x , y , z ; Split(rt , r , x , z) ; Split(x , l - 1 , x , y) ; tr[y].rev ^= 1 ; rt = Merge(x , Merge(y , z)) ; } ll Query(int & rt , int l , int r) { int x , y , z ; Split(rt , r , x , z) ; Split(x , l - 1 , x , y) ; ll ans = tr[y].sum ; rt = Merge(x , Merge(y , z)) ; return ans ; } int main() { srand(19260817) ; n = read() ; for(int i = 1 ; i <= n ; i ++) { int ver = read() , opt = read() ; ll x = read() ^ lastans , y ; rt[i] = rt[ver] ; if(opt != 2) { y = read() ^ lastans ; } if(opt == 1) { Insert(rt[i] , x , y) ; } if(opt == 2) { Remove(rt[i] , x) ; } if(opt == 3) { Reverse(rt[i] , x , y) ; } if(opt == 4) { print(lastans = Query(rt[i] , x , y)) ; } } return 0 ; }
可持久化trie树的话就…
int tot = 0 ; int t[N] ; int ch[N << 5][2] ; int sz[N << 5] ; inline void upd(int x , int p , int q) { ch[p][0] = ch[q][0] ; ch[p][1] = ch[q][1] ; sz[p] = sz[q] + 1 ; for(register int i = 29 ; ~ i ; i --) { int c = (x >> i) & 1 ; ch[p][c] = ++ tot ; p = ch[p][c] ; q = ch[q][c] ; ch[p][0] = ch[q][0] ; ch[p][1] = ch[q][1] ; sz[p] = sz[q] + 1 ; } } inline int query(int x , int p , int q) { int res = 0 ; for(register int i = 29 ; ~ i ; i --) { int c = (x >> i) & 1 ; if(sz[ch[q][c ^ 1]] - sz[ch[p][c ^ 1]]) res |= 1 << i , p = ch[p][c ^ 1] , q = ch[q][c ^ 1] ; else p = ch[p][c] , q = ch[q][c] ; } return res ; }
之后咕咕咕咕。。有空再填坑…