可持久化应该都知道…
就是可以回退历史版本…以及区间查询一些东西比如说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()

#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 ;
}

之后咕咕咕咕。。

12-26 13:45