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