可持久化[学习笔记]

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

可持久化的题目…
高级打字机

#include<bits/stdc++.h>
using namespace std ;
int n ;
const int N = 1e5 + 10 ;
int rt[N] , cnt[N] ;
int ls[N << 5] , rs[N << 5] ;
char val[N << 5] ;
int tot = 0 , num = 0 ;
inline void build(int l , int r , int & o) {
  o = ++ tot ;
  if(l == r) { return ; }
  int mid = l + r >> 1 ;
  build(l , mid , ls[o]) ;
  build(mid + 1 , r , rs[o]) ;
}
inline void upd(int x , int l , int r , int pre , int & o , char c) {
  ls[o = ++ tot] = ls[pre] ;
  rs[o] = rs[pre] ;
  if(l == r) { val[o] = c ; return ; }
  int mid = l + r >> 1 ;
  if(x <= mid) upd(x , l , mid , ls[pre] , ls[o] , c) ;
  else upd(x , mid + 1 , r , rs[pre] , rs[o] , c) ;
}
inline char query(int x , int l , int r , int o) {
  if(l == r) return val[o] ;
  int mid = l + r >> 1 ;
  if(x <= mid) return query(x , l , mid , ls[o]) ;
  else return query(x , mid + 1 , r , rs[o]) ;
}
signed main() {
#ifdef _WIN64
  freopen("0.in" , "r" , stdin) ;
#endif
  ios :: sync_with_stdio(false) ;
  cin.tie(nullptr) ; cout.tie(nullptr) ;
  cin >> n ;
  build(1 , n , rt[0]) ;
  for(register int i = 1 ; i <= n ; i ++) {
    char opt ; cin >> opt ;
    if(opt == 'T') { char c ; cin >> c ; ++ num ; upd(cnt[num] = cnt[num - 1] + 1 , 1 , n , rt[num - 1] , rt[num] , c) ; }
    if(opt == 'U') { int x ; cin >> x ; ++ num ; cnt[num] = cnt[num - x - 1] ; rt[num] = rt[num - x - 1] ; }
    if(opt == 'Q') { int x ; cin >> x ; cout << query(x , 1 , n , rt[num]) << '\n' ; }
  }
  return 0 ;
}

Count on a tree

每次记下LCA 和 FA[LCA]就可以了吧

// 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 = 1e5 + 10 ;
const int M = N << 5 ;
int n , q ; int m ;
int sum[M] , L[M] , R[M] ;
int a[N] , b[N] , rt[N] ;
struct node{
	int v ;
	int nxt ;
};
node e[N << 1] ;
int head[N] ;
int fa[N] , size[N] , d[N] , son[N] , top[N] ;
int cnt =  0 ; 
inline void Add(int u , int v) {
	e[ ++ cnt] . v = v ;
	e[ cnt] . nxt = head[u] ;
	head[u] = cnt ;
	return ;
}
int tot = 0 ;
inline void Update(int last , int & now , int l , int r , int x) {
	sum[now = ++ tot] = sum[last] + 1 ;
	if(l == r) return ;
	int mid = l + r >> 1 ;
	if(x <= mid) R[now] = R[last] , Update(L[last] , L[now] , l , mid , x) ;
	else L[now] = L[last] , Update(R[last] , R[now] , mid + 1 , r , x) ;
	return ;
}
inline int Query(int a , int b , int lca ,int lca_fa , int l , int r , int k) {
	if(l >= r) return l ;
	int x = sum[L[a]] + sum[L[b]] - sum[L[lca]] - sum[L[lca_fa]] ;
	int mid = l + r >> 1 ;
	if(x >= k) return Query(L[a] , L[b] , L[lca] , L[lca_fa] , l , mid , k) ;
	else return Query(R[a] , R[b] , R[lca] , R[lca_fa] , mid + 1 , r , k - x) ;
}

inline void Dfs(int u) {
	size[u] = 1 ;
	Update(rt[fa[u]] , rt[u] , 1 , m , a[u]) ;
	for(register int i = head[u] ; i ; i = e[i].nxt) {
		int v = e[i].v ;
		if(v == fa[u]) continue ;
		fa[v] = u  ;
		d[v] = d[u] + 1 ;
		Dfs(v) ;
		size[u] += size[v] ;
		if(size[v] > size[son[u]]) son[u] = v ;
	}
}
inline void Dfs2(int u , int t) {
	top[u] = t ;
	if(! son[u]) return ;
	Dfs2(son[u] , t) ;
	for(register int i = head[u] ; i ; i = e[i].nxt) {
		int v = e[i].v ;
		if(v ^ fa[u] && v ^ son[u]) Dfs2(v , v) ;
	}
}
inline int Lca(int x , int y) {
	int fx = top[x] ;
	int fy = top[y] ;
	while(fx ^ fy) {
		if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
		x = fa[fx] ;
		fx = top[x] ;
	}
	if(d[x] > d[y]) swap(x , y) ;
	return x ;
}
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() ;
	for(register int i = 1 ; i <= n ; i ++) b[i] = a[i] ;
	sort(b + 1 , b + n + 1) ;
	m = unique(b + 1 , b + 1 + n) - b - 1 ;
	for(register int i = 1 ; i <= n ; i ++) 
		a[i] = lower_bound(b + 1 , b + m + 1 , a[i]) - b ;
	for(register int i = 1 ; i <= n - 1 ; i ++) {
		int u = read() , v = read() ;
		Add(u , v) ;
		Add(v , u) ;
	}
	Dfs(1) ;
	Dfs2(1 , 1) ;
	int ans = 0 ;
	for(register int i = 1 ; i <= q ; i ++) {
		int x = read() ^ ans , y = read() ;
		int lca = Lca(x , y) ;
		int z = read() ;
		write(ans = b[Query(rt[x] , rt[y] , rt[lca] , rt[fa[lca]] , 1 , m , z)]) ;
	}
	return 0 ;
}

[POI2014]KUR-Couriers
板子…

// 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 = 5e5 + 5 ;
struct node {
	int l , r , sum ;
};
int a[N] ;
node T[N << 5] ;
int n , m , root[N] , cnt = 1 ;

inline void Insert(int & p , int l , int r , int x) {
	T[cnt ++] = T[p] ; p = cnt - 1 ;
	T[p].sum ++ ;
	if(l == r) return ;
	int mid = l + r >> 1 ;
	if(x <= mid) Insert(T[p].l , l , mid , x) ;
	else Insert(T[p].r , mid + 1 , r , x) ;
}
inline int Query(int a , int b , int l , int r , int len) {
	if(l == r) return l ;
	int mid = l + r >> 1 ;
	if(T[T[b].l].sum - T[T[a].l].sum << 1 > len) return Query(T[a].l , T[b].l , l , mid , len) ;
	if(T[T[b].r].sum - T[T[a].r].sum << 1 > len) return Query(T[a].r , T[b].r , mid + 1 , r , len) ;
	return 0 ;
}
signed main() {
#ifdef Online_Judge
	freopen("testdata.in" , "r" , stdin) ;
	freopen("testdata2.out" , "w" , stdout) ;
#endif
	n = read() ; m = read() ;
	for(register int i = 1 ; i <= n ; i ++) a[i] = read() ;
	for(register int i = 1 ; i <= n ; i ++) Insert(root[i] = root[i - 1] , 1 , n , a[i]) ;
	for(register int i = 1 ; i <= m ; i ++) {
		int l = read() , r = read() ;
		printf("%d\n" , Query(root[l - 1] , root[r] , 1 , n , r - l + 1)) ;
	}
	return 0 ;
}

一堆题
懒得写解法自己看呗…
[CQOI2015]任务查询系统

// luogu-judger-enable-o2
// Isaunoya

#include<bits/stdc++.h>

using namespace std ;
inline void Open() {
	ios::sync_with_stdio(0) ;
	cin.tie(0) ;
	cout.tie(0) ;
}

int n , q ;
const int N = 2e5 + 5 ;
const int M = N << 5 ;
int ls[M] , rs[M] , num[M] , rt[N] , sp[N] ;
long long sum[M] ;
struct node {
	int v ;
	int nxt ;
};
int head[N] ;
node e[N << 1] ;
int cnt = 0 ;
inline void Add(int u , int v) {
	e[++ cnt].v = v ;
	e[cnt].nxt = head[u] ;
	head[u] = cnt ;
	return ;
}
inline int abs(int x){ return x>0?x:-x;}
inline int max(int x , int y) { return x > y ? x : y ;}
int tot = 0 ;
inline void  Upd(int & p , int last , int l , int r , int x) {
	if(! p) p = ++ tot ;
	num[p] = num[last] + (x < 0 ? -1 : 1) ;
	sum[p] = sum[last] + x ;
	if(l == r) return ;
	int mid = l + r >> 1 ;
	if(abs(x) <= mid) {
		rs[p] = rs[last] ;
		Upd(ls[p] , ls[last] , l , mid , x) ;
	}
	else {
		ls[p] = ls[last] ;
		Upd(rs[p] , rs[last] , mid + 1 , r , x) ;
	}
}
inline long long Query(int l , int r , int u , int k) {
	if(l == r) return k * l ;
	int mid = l + r >> 1 ;
	if(k <= num[ls[u]]) return Query(l , mid , ls[u] , k) ;
	else return Query(mid + 1 , r , rs[u] , k - num[ls[u]]) + sum[ls[u]] ; 
}
signed main() {
	Open() ;
	cin >> n >> q ;
	int maxn = -1e9 ;
	for(register int i = 1 ; i <= n ; i ++) {
		int u , v , e ;
		cin >> u >> v >> e ;
		Add(u , e) ;
		Add(v + 1 , -e) ;
		maxn = max(maxn , e) ;
	}
	int m = 0 ;
	for(register int u = 1 ; u <= n ; u ++) {
		for(register int i = head[u] ; i ; i = e[i].nxt) {
			m ++ ;
			Upd(rt[m] , rt[m - 1] , 1 , maxn , e[i].v) ; 
		} 
		sp[u] = m ;
	}
	long long ans = 1 ;
	for(register int i = 1 ; i <= q ; i ++) {
		int x , a , b , c ;
		cin >> x >> a >> b >> c ;
		long long k = (1LL * a * ans + b) % c + 1 ;
		ans = (num[rt[sp[x]]] <= k) ? sum[rt[sp[x]]] : Query(1 , maxn , rt[sp[x]] , k) ;
		cout << ans << endl ;
	}
	return 0 ;
}

[SCOI2016]美味

// luogu-judger-enable-o2
#include<iostream>
using namespace std ;
int n , m ;
const int N = 5e5 + 5 ;
int a[N] ;
int cnt , t[N << 5] , ch[N << 5][2] , sum[N << 5] ;
inline void Upd(int pos , int pre , int l , int r , int & p) {
	if(r < pos || l > pos) return ;
	p = ++ cnt ;
	ch[p][0] = ch[pre][0] ;
	ch[p][1] = ch[pre][1] ;
	sum[p] = sum[pre] + 1 ;
	if(l == r) {
		return ;
	}
	int mid = l + r >> 1 ;
	Upd(pos , ch[pre][0] , l , mid , ch[p][0]) ;
	Upd(pos , ch[pre][1] , mid + 1 , r , ch[p][1]) ;
}
inline int Query(int u , int v , int  a , int b , int l , int r) {
	int num = sum[v] - sum[u] , mid = l + r >> 1 ;
	if(b < l || a > r || ! num) return 0 ;
	if(a <= l && r <= b) return num ;
	return Query(ch[u][0] , ch[v][0] , a , b , l , mid) + Query(ch[u][1] , ch[v][1] , a , b , mid + 1 , r) ;
}
inline int max(register int x , register int y) {
	return x > y ? x : y ;
}
signed main() {
	ios::sync_with_stdio(0) , cin.tie(0) , cout.tie(0) ;
	cin >> n >> m ;
	int mx = -1e9 ;
	for(register int i = 1 ; i <= n ; i ++) cin >> a[i] ;
	for(register int i = 1 ; i <= n ; i ++) mx = max(a[i] , mx) ;
	for(register int i = 1 ; i <= n ; i ++) {
		Upd(a[i] , t[i - 1] , 0 , mx , t[i]) ;
	}
	for( ; m -- ; ) {
		register int b , x , l , r ;
		cin >> b >> x >> l >> r ;
		int ans = 0 ;
		for(register int i = 18 ; i >= 0 ; i --) {
			if(b & (1 << i) && ! Query(t[l - 1] , t[r] , ans - x , ans - x + (1 << i) - 1 , 0 , mx)) ans += 1 << i ;
            if(! (b & (1 << i)) && Query(t[l - 1] , t[r] , ans - x + (1 << i) , ans - x + (1 << i + 1) - 1 , 0 , mx)) ans += 1 << i ;
		}
		cout << (ans ^ b) << endl ;
	}
	return 0 ;
}

Rmq Problem / mex

这题提供三种做法…

#include<bits/stdc++.h>
using namespace std ;
inline int min(int x , int y) { return x < y ? x : y ; }
int n , m ;
const int N = 1e6 + 10 ;
int a[N] , mn[N << 2] ;
typedef pair < int , int > pii ;
vector < pii > vr[N] ;
inline void update(int x , int l , int r , int rt , int val) {
  if(l == r) { mn[rt] = val ; return ; }
  int mid = l + r >> 1 ;
  if(x <= mid) update(x , l , mid , rt << 1 , val) ;
  else update(x , mid + 1 , r , rt << 1 | 1 , val) ;
  mn[rt] = min(mn[rt << 1] , mn[rt << 1 | 1]) ;
}
inline int query(int a , int b , int l , int r , int rt) {
  if(a <= l && r <= b) { return mn[rt] ; }
  int mid = l + r >> 1 , ans = INT_MAX ;
  if(a <= mid) ans = min(ans , query(a , b , l , mid , rt << 1)) ;
  if(b > mid) ans = min(ans , query(a , b , mid + 1 , r , rt << 1 | 1)) ;
  return ans ;
}
struct pri_que {
  priority_queue < int , vector < int > , greater < int > > a , b ;
  inline void push(int x) { a.push(x) ; }
  inline void pop(int x) { b.push(x) ; }
  inline int top() { while(a.top() == b.top()) { a.pop() ; b.pop() ; } return a.top() ; }
} q ;
int las[N] , ans[N] ;
bool vis[N] ;
signed main() {
#ifdef _WIN64
  freopen("a.in" , "r" , stdin) ;
#endif
  ios :: sync_with_stdio(false) ; cin.tie(nullptr) ; cout.tie(nullptr) ;
  cin >> n >> m ;
  for(register int i = 1 ; i <= n ; i ++) cin >> a[i] ;
  for(register int i = 1 ; i <= m ; i ++) { int l , r ; cin >> l >> r ; vr[r].push_back(pii(l , i)) ; }
  for(register int i = 0 ; i <= 1e6 ; i ++) q.push(i) ;
  for(register int i = 1 ; i <= n ; i ++) {
    if(! vis[a[i]]) vis[a[i]] = 1 , q.pop(a[i]) ;
    if(las[a[i]]) update(las[a[i]] , 1 , n , 1 , INT_MAX) ;
    las[a[i]] = i ; update(i , 1 , n , 1 , a[i]) ;
    for( pii x : vr[i] ) {
      ans[x.second] = q.top() ;
      if(x.first > 1) { ans[x.second] = min(ans[x.second] , query(1 , x.first - 1 , 1 , n , 1)) ; }
    }
  }
  for(register int i = 1 ; i <= m ; i ++) cout << ans[i] << '\n' ;
  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
int n , m ;
const int N = 200000 + 5 ;
int a[N] ;
int vis[N + 10] ;
struct node {
	int l , r ;
	int id ;
};
node q[N] ;
int unt ;
int ans = 0 ;
int Answer[N] ;
inline bool cmp(node x , node y) {
	if(x.l / unt ^ y.l / unt) return x.l < y.l ;
	if(x.r ^ y.r) return x.r < y.r ;
	return x.id < y.id ;
}
inline void Ins(int x) {
	if(x > N) return ;
	vis[x] ++ ;
	if(vis[x] > 1) return ;
	if(x == ans) {
		while(vis[ans]) ans ++ ;
		return ;
	}
}
inline void Del(int x) {
	if(x > N) return ;
	vis[x] -- ;
	if(vis[x] == 0) ans = min(ans , x) ;
}
signed main() {
#ifdef Online_Judge
	freopen("testdata.in" , "r" , stdin) ;
	freopen("testdata2.out" , "w" , stdout) ;
#endif
	n = read() , m = read() ; unt = sqrt(n) ;
	for(register int i = 1 ; i <= n ; i ++) a[i] = read() ;
	for(register int i = 1 ; i <= m ; i ++) {
		int l = read() , r = read() ;
		q[i] = {l , r , i} ;
	}
	sort(q + 1 , q + m + 1 , cmp) ;
	int l = 1 , r = 0 ;
	for(register int i = 1 ; i <= m ; i ++) {
		for( ; l < q[i].l ; Del(a[l ++])) ;
		for( ; l > q[i].l ; Ins(a[-- l])) ;
		for( ; r < q[i].r ; Ins(a[++ r])) ;
		for( ; r > q[i].r ; Del(a[r --])) ;
		Answer[q[i].id] = ans ;
	}
	for(register int i = 1 ; i <= m ; i ++) write(Answer[i]) ;
	return 0 ;
}
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std ;
int n , q ;
const int N = 1e6 + 10 ;
int ls[N * 40] , rs[N * 40] , rt[N] , v[N * 40] ;
int cnt = 0 ;
inline int min(int x , int y) { return x < y ? x : y ; }
inline void build(int l , int r , int & o) {
  o = ++ cnt ;
  if(l == r) return ;
  int mid = l + r >> 1 ;
  build(l , mid , ls[o]) ;
  build(mid + 1 , r , rs[o]) ;
}
inline void update(int l , int r , int pre , int & o , int val , int x) {
  o = ++ cnt ; ls[o] = ls[pre] ; rs[o] = rs[pre] ;
  if(l == r) { v[o] = x ; return ; }
  int mid = l + r >> 1 ;
  if(val <= mid) update(l , mid , ls[pre] , ls[o] , val , x) ;
  else update(mid + 1 , r , rs[pre] , rs[o] , val , x) ;
  v[o] = min(v[ls[o]] , v[rs[o]]) ;
}
int goal = 0 ;
inline int query(int l , int r , int o) {
  if(l == r) return l ;
  int mid = l + r >> 1 ;
  if(v[ls[o]] < goal) return query(l , mid , ls[o]) ;
  else return query(mid + 1 , r , rs[o]) ;
}
const int L = 0 , R = 1e6 + 1 ;
signed main() {
#ifdef _WIN64
  freopen("a.in" , "r" , stdin) ;
#endif
  ios :: sync_with_stdio(false) ;
  cin.tie(nullptr) ;
  cout.tie(nullptr) ;
  cin >> n >> q ;
  build(L , R , rt[0]) ;
  for(register int i = 1 ; i <= n ; i ++) {
    int x ; cin >> x ;
    update(L , R , rt[i - 1] , rt[i] , x , i) ;
  }
  while(q --) {
    int l , r ; cin >> l >> r ;
    goal = l ; cout << query(L , R , rt[r]) << '\n' ;
  }
  return 0 ;
}

还有个可持久化trie树

最大异或和

// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define rep(i , j , n) for(register int i=j;i<=n;i++)
#define Rep(i , j , n) for(register int i=j;i>=n;i--)
#define gc c = getchar()
inline int read() { register int x = 0 , f = 1 ; register char c ;
	while(isspace(gc)) ; c == '-' ? f = -1 , gc : 0 ;
	while((x *= 10) += (c ^ 48) , isdigit(gc)) ;
	return x * f ;
}

using namespace std ;


const int N = 3000000 + 5 ;

int n , m , Sum ;
int l , r , x , k ;
int tree[N << 5][2] ;
int root[N << 5] ;
int sum[N << 5] ;
int d[40] ;
int cnt ;
inline void Split(int k) {
	int l = 0 ;
	while(k) {
		d[++ l] = k & 1 ;
		k >>= 1 ;
	}
	for(register int i=l+1;i<=27;i++) d[i] = 0 ;
}
inline void Build(int x , int & y) {
	cnt ++ ; y = cnt ;
	sum[y] = sum[x] + 1 ;
	int now = y ;
	for(register int i=27;i>=1;i--) {
		tree[now][d[i]^1] = tree[x][d[i]^1] ;
		cnt ++ ;
		tree[now][d[i]] = cnt ;
		now = cnt ;
		x = tree[x][d[i]] ;
		sum[now] = sum[x] + 1 ;
	}
}
inline int Query(int x , int y) {
	int ans = 0 ;
	for(register int i=27;i>=1;i--) {
		if(sum[tree[y][d[i]^1]] - sum[tree[x][d[i]^1]] > 0) {
			ans += 1 << i - 1 ;
			y = tree[y][d[i]^1] ;
			x = tree[x][d[i]^1] ;
		}
		else {
			y = tree[y][d[i]] ;
			x = tree[x][d[i]] ;
		}
	}
	return ans ;
}
signed main() {
//	freopen("text.in" , "r" , stdin) ;
//	freopen("text.out" , "w" , stdout) ;
	n = read() , m = read() ;
	cnt = 0 ; Split(0) ;
	tree[0][0] = tree[0][1] = root[0] = 0 ;
	Build(root[0] , root[1]) ;
	n ++ ; Sum = 0 ;
	for(register int i=2;i<=n;i++) {
		x = read() ;
		Sum ^= x ;
		Split(Sum) ;
		Build(root[i - 1] , root[i]) ;
	}
	char s[10] ;
	for(register int i=1;i<=m;i++) {
		scanf("%s" , s) ;
		if(s[0] == 'A') {
			n ++ ;
			x = read() ;
			Sum ^= x ;
			Split(Sum) ;
			Build(root[n - 1] , root[n]) ;
		}
		else {
			l = read() , r = read() , k = read() ;
			k ^= Sum ;
			Split(k) ;
			printf("%d\n" , Query(root[l - 1] , root[r])) ;
		}
	}
	return 0 ;
}

之后咕咕咕咕。。有空再填坑…

posted @ 2019-12-02 13:12  _Isaunoya  阅读(233)  评论(0编辑  收藏  举报