训练计划Day2

Day2:线段树(可持久化),平衡树(splay,treap),并查集,树链剖分,动态树,树状数组,点分治(可持久)。

  • 线段树模板

//区间最大,and,or
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline void read(int &x){
    x=0;static char ch;static bool flag;flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);++i)
const int maxn = 100010;
const int bas = 0x7fffffff;
int T[maxn<<2],lazy[maxn<<2],sam[maxn<<2];
int a[maxn];
inline void update(int rt){
    T[rt] = max(T[rt<<1],T[rt<<1|1]);
    sam[rt] = (sam[rt<<1]&sam[rt<<1|1]) & (~(T[rt<<1]^T[rt<<1|1]));
}
inline void pushdown(int rt){
    if(lazy[rt] == 0) return ;
    T[rt<<1] += lazy[rt];lazy[rt<<1] += lazy[rt];
    T[rt<<1|1] += lazy[rt];lazy[rt<<1|1] += lazy[rt];
    lazy[rt] = 0;
}
void build(int rt,int l,int r){
    if(l == r){
        T[rt] = a[l];
        sam[rt] = bas;
        return ;
    }int mid = l+r >> 1;
    build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
    update(rt);
}
int L,R,val,tmp;
inline bool check_a(int rt){
    tmp = (val^bas);
    return (tmp & sam[rt]) == tmp;
}
void modify_a(int rt,int l,int r){
    if(L <= l && r <= R && check_a(rt)){
        tmp = (T[rt] & val) - T[rt];
        lazy[rt] += tmp;T[rt] += tmp;
        return ;
    }int mid = l+r >> 1;pushdown(rt);
    if(L <= mid) modify_a(rt<<1,l,mid);
    if(R >  mid) modify_a(rt<<1|1,mid+1,r);
    update(rt);
}
void modify_o(int rt,int l,int r){
    if(L <= l && r <= R && (sam[rt] & val) == val){
        tmp = (T[rt] | val) - T[rt];
        lazy[rt] += tmp;T[rt] += tmp;
        return ;
    }int mid = l+r >> 1;pushdown(rt);
    if(L <= mid) modify_o(rt<<1,l,mid);
    if(R >  mid) modify_o(rt<<1|1,mid+1,r);
    update(rt);
}
int query(int rt,int l,int r){
    if(L <= l && r <= R) return T[rt];
    int mid = l+r >> 1;pushdown(rt);
    if(R <= mid) return query(rt<<1,l,mid);
    if(L >  mid) return query(rt<<1|1,mid+1,r);
    return max(query(rt<<1,l,mid),query(rt<<1|1,mid+1,r));
}
int main(){
    //freopen("series_wei.in","r",stdin);
    //freopen("series_wei.out","w",stdout);
    int n,m;read(n);read(m);
    rep(i,1,n) read(a[i]);
    build(1,1,n);int opt;
    int cnt = 0 ;
    while(m--){
        read(opt);read(L);read(R);
        if(opt == 1) read(val),modify_a(1,1,n);
        else if(opt == 2) read(val),modify_o(1,1,n);
        else printf("%d\n",query(1,1,n));
    }
    return 0;
}
//poj 3225 线段树成段替换与异或
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
 
const int maxn = 131072;
bool hash[maxn];
int cover[maxn<<2];
int XOR[maxn<<2];
void FXOR(int rt) {
       if (cover[rt] != -1) cover[rt] ^= 1;
       else XOR[rt] ^= 1;
}
void PushDown(int rt) {
       if (cover[rt] != -1) {
              cover[rt<<1] = cover[rt<<1|1] = cover[rt];
              XOR[rt<<1] = XOR[rt<<1|1] = 0;
              cover[rt] = -1;
       }
       if (XOR[rt]) {
              FXOR(rt<<1);
              FXOR(rt<<1|1);
              XOR[rt] = 0;
       }
}
void update(char op,int L,int R,int l,int r,int rt) {
       if (L <= l && r <= R) {
              if (op == 'U') {
                     cover[rt] = 1;
                     XOR[rt] = 0;
              } else if (op == 'D') {
                     cover[rt] = 0;
                     XOR[rt] = 0;
              } else if (op == 'C' || op == 'S') {
                     FXOR(rt);
              }
              return ;
       }
       PushDown(rt);
       int m = (l + r) >> 1;
       if (L <= m) update(op , L , R , lson);
       else if (op == 'I' || op == 'C') {
              XOR[rt<<1] = cover[rt<<1] = 0;
       }
       if (m < R) update(op , L , R , rson);
       else if (op == 'I' || op == 'C') {
              XOR[rt<<1|1] = cover[rt<<1|1] = 0;
       }
}
void query(int l,int r,int rt) {
       if (cover[rt] == 1) {
              for (int it = l ; it <= r ; it ++) {
                     hash[it] = true;
              }
              return ;
       } else if (cover[rt] == 0) return ;
       if (l == r) return ;
       PushDown(rt);
       int m = (l + r) >> 1;
       query(lson);
       query(rson);
}
int main() {
       cover[1] = XOR[1] = 0;
       char op , l , r;
       int a , b;
       while ( ~scanf("%c %c%d,%d%c\n",&op , &l , &a , &b , &r) ) {
              a <<= 1 , b <<= 1;
              if (l == '(') a ++;
              if (r == ')') b --;
              if (a > b) {
                     if (op == 'C' || op == 'I') {
                            cover[1] = XOR[1] = 0;
                     }
              } else update(op , a , b , 0 , maxn , 1);
       }
       query(0 , maxn , 1);
       bool flag = false;
       int s = -1 , e;
       for (int i = 0 ; i <= maxn ; i ++) {
              if (hash[i]) {
                     if (s == -1) s = i;
                     e = i;
              } else {
                     if (s != -1) {
                            if (flag) printf(" ");
                            flag = true;
                            printf("%c%d,%d%c",s&1?'(':'[' , s>>1 , (e+1)>>1 , e&1?')':']');
                            s = -1;
                     }
              }
       }
       if (!flag) printf("empty set");
       puts("");
       return 0;
}
//树状数组扫描线
#include<vector>
#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;
const int Maxn=4005;
const int Maxp=1e5+5;

struct node{
    int up,low,v;
};
struct node2{
    int p,id;
};
int n,m,p,q;
int ans[Maxp],tr[4*Maxn];
vector<node> lne[Maxn];
vector<node2> ask[Maxn];

inline int lowbit(int x){
    return x&(-x);
}
inline void read(int &x){
    x=0; int f=1; char ch;
    do{ch=getchar(); if(ch=='-') f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0'; ch=getchar();} while(ch>='0'&&ch<='9');
    x*=f;
}
void add(int x,int v){
    for(int i=x;i<=n;i+=lowbit(i))
        tr[i]+=v;
}
int srch(int x){
    int sum=0;
    for(int i=x;i;i-=lowbit(i))
        sum+=tr[i];
    return sum;
}
int main(){
    read(n),read(m),read(p),read(q);
    for(int i=1;i<=p;i++){
        int a,b,c,d;
        read(a),read(b),read(c),read(d);
        node stp;
        stp.up=a,stp.low=c,stp.v=1;
        lne[b].push_back(stp);
        stp.v=-1;
        lne[d+1].push_back(stp);
    }
    for(int i=1;i<=q;i++){
        int a,b; node2 stp;
        read(a),read(b);
        stp.p=a,stp.id=i;
        ask[b].push_back(stp);
    }
    for(int i=1;i<=m;i++){
        int len=lne[i].size();
        for(int j=0;j<len;j++)
            add(lne[i][j].up   , lne[i][j].v),
            add(lne[i][j].low+1,-lne[i][j].v);
        len=ask[i].size();
        for(int j=0;j<len;j++)
            ans[ask[i][j].id]=srch(ask[i][j].p);
    }
    for(int i=1;i<=q;i++)
        printf("%d\n",ans[i]);
    return 0;
} 
//可持久线段树k小
#include<bits/stdc++.h>
using namespace std;

const int maxn = 3000010;

struct node{
    int l;
    int r;
    int sum;
}t[maxn<<2];

struct Node{
    int p;
    int id;
}Nod[maxn<<2];

int n;
int rt[maxn];
int a[maxn];
int v[maxn];
int m;
int cnt;

inline bool cmp(const Node &x,const Node &y) {
    return x.p < y.p;
}

inline void build(int l,int r,int &p,int pos) {
    ++cnt;
    t[cnt] = t[p];
    p = cnt;
    ++t[p].sum;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(pos <= mid) {
        build(l,mid,t[p].l,pos);
    }
    else {
        build(mid+1,r,t[p].r,pos);
    }
    return;
}

inline int query(int l,int r,int L,int R,int k) {
    if(l == r) return l;
    int c = t[t[R].l].sum - t[t[L].l].sum;
    int mid = (l + r) >> 1;
    if(c >= k) {
        return query(l,mid,t[L].l,t[R].l,k);
    }
    else {
        return query(mid +1 ,r,t[L].r,t[R].r,k - c);
    }
}
int l,r,k;

int main (){
    cin >> n >> m;
    for(int i = 1;i <= n; ++i) {
        cin >> Nod[i].p;
        Nod[i].id = i;      
    }
    sort(Nod+1,Nod+n+1,cmp);
    for(int i = 1;i <= n; ++i) {
        a[Nod[i].id] = i;
        v[i] = Nod[i].p;
    }
    for(int i = 1;i <= m; ++i) {
        rt[i] = rt[i - 1];
        build(1,n,rt[i],a[i]);
    }
    while(m--) {
        cin >> l >> r >> k;
        cout<<v[query(1,n,rt[l-1],rt[r],k)]<<endl;
    }
    return 0;
}
//可持久线段树历史区间最大,历史单点修改
#include<cstdio>
const int maxn=1e4+10;
const int maxq=1e5+10;
int n,q,ts,ks;
int a,b,c,d;
int tt[maxq];
struct tree{int s,l,r,mid,lp,rp;}t[maxq<<4];
inline int min_(int x,int y){return x<y?x:y;}
inline int max_(int x,int y){return x>y?x:y;}
void build(int l,int r,int k){
    t[k].l=l,t[k].r=r;
    if(l==r){scanf("%d",&t[k].s);return;}
    t[k].mid=l+r>>1,t[k].lp=++ts,t[k].rp=++ts;
    build(l,t[k].mid,t[k].lp);
    build(t[k].mid+1,r,t[k].rp);
    t[k].s=max_(t[t[k].lp].s,t[t[k].rp].s);
}
void change(int k,int nk){
    t[nk].l=t[k].l,t[nk].r=t[k].r;
    if(t[k].l==t[k].r){t[nk].s=d;return;}
    t[nk].mid=t[k].mid;
    if(c<=t[k].mid){
        t[nk].lp=++ts,t[nk].rp=t[k].rp;
        change(t[k].lp,t[nk].lp);
    }
    else{
        t[nk].rp=++ts,t[nk].lp=t[k].lp;
        change(t[k].rp,t[nk].rp);
    }
    t[nk].s=max_(t[t[nk].lp].s,t[t[nk].rp].s);
}
int search(int k,int l,int r){
    if(t[k].l==l&&t[k].r==r) return t[k].s;
    int ans=0;
    if(l<=t[k].mid) ans=search(t[k].lp,l,min_(r,t[k].mid));
    if(r>t[k].mid) ans=max_(ans,search(t[k].rp,max_(l,t[k].mid+1),r));
    return ans;
}
int main(){
    scanf("%d%d",&n,&q);
    build(1,n,tt[++ks]);
    while(q--){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        if(a){
            tt[++ks]=++ts;
            change(tt[b],tt[ks]);
        }
        else printf("%d\n",search(tt[b],c,d));
    }
    return 0;
}
//线段树扫描线
// luogu-judger-enable-o2
#include<vector>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define getchar() getchar()_locked
#define getchar() (S==T&&(T=(S=BB)+fread(BB,1,1<<15,stdin),S==T)?EOF:*S++)
char BB[1<<15];
char *S=BB;
char *T=BB;
using namespace std;
const int Maxn=4005;
const int Maxp=1e5+5;

struct node{
    int up,low,v;
};
struct node2{
    int p,id;
};
struct node3{
    int l,r,sum,lazy;
}tr[4*Maxn];
int ans[Maxp];
vector<node> lne[Maxn];
vector<node2> ask[Maxn];

inline void read(int &x){
    x=0; int f=1; char ch;
    do{ch=getchar(); if(ch=='-') f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0'; ch=getchar();} while(ch>='0'&&ch<='9');
    x*=f;
}
void build(int p,int x,int y){
    tr[p].l=x,tr[p].r=y,tr[p].sum=0,tr[p].lazy=0;
    if(x==y) return ;
    int mid=(x+y)/2;
    build(p*2,x,mid),build(p*2+1,mid+1,y);
}
void push_down(int p){
    if(!tr[p].lazy) return ;
    tr[p * 2].sum+=(tr[p * 2].r-tr[p * 2].l+1)*tr[p].lazy;
    tr[p*2+1].sum+=(tr[p*2+1].r-tr[p*2+1].l+1)*tr[p].lazy;
    tr[p * 2].lazy+=tr[p].lazy;
    tr[p*2+1].lazy+=tr[p].lazy;
    tr[p].lazy=0;
}
void add(int p,int x,int y,int v){
    int nl=tr[p].l,nr=tr[p].r;
    if(nl==nr){
        tr[p].sum+=(nr-nl+1)*v;
        tr[p].lazy+=v;
        return ;
    }
    push_down(p);
    int mid=(nl+nr)/2;
    if(y<=mid) add(p*2,x,y,v);
    else if(x>mid) add(p*2+1,x,y,v);
    else add(p*2,x,mid,v),add(p*2+1,mid+1,y,v);
    tr[p].sum=tr[p*2].sum+tr[p*2+1].sum;
    return ;
}
int srch(int p,int x){
    int nl=tr[p].l,nr=tr[p].r;
    if(nl==nr)
        return tr[p].sum;
    push_down(p);
    int mid=(nl+nr)/2;
    if(x<=mid) return srch(p*2,x);
    else return srch(p*2+1,x);
}
int main(){
    int n,m,p,q; 
    read(n),read(m),read(p),read(q);
    build(1,1,n);
    for(int i=1;i<=p;i++){
        int a,b,c,d;
        read(a),read(b),read(c),read(d);
        node stp;
        stp.up=a,stp.low=c,stp.v=1;
        lne[b].push_back(stp);
        stp.v=-1;
        lne[d+1].push_back(stp);
    }
    for(int i=1;i<=q;i++){
        int a,b; node2 stp;
        read(a),read(b);
        stp.p=a,stp.id=i;
        ask[b].push_back(stp);
    }
    for(int i=1;i<=m;i++){
        int len=lne[i].size();
        for(int j=0;j<len;j++)
            add(1,lne[i][j].up,lne[i][j].low,lne[i][j].v);
        len=ask[i].size();
        for(int j=0;j<len;j++)
            ans[ask[i][j].id]=srch(1,ask[i][j].p);
    }
    for(int i=1;i<=q;i++)
        printf("%d\n",ans[i]);
    return 0;
} 
//待修改k小
// luogu-judger-enable-o2
//bzoj 3065
#include<bits/stdc++.h>
using namespace std;
#define MAXN    700005
#define MAXV    700005
#define MAXP    20009999
#define ALPHA   0.68
template <typename T> void read(T &x) {
    x = 0; int f = 1;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
    x *= f;
}
void getopt(char &c) {
    c = getchar();
    while (c != 'Q' && c != 'I' && c != 'M')
        c = getchar();
}
struct Segment_Tree {
    int now, root[MAXN];
    int top, mem[MAXP];
    int lc[MAXP], rc[MAXP], sum[MAXP];
    void init(int n) {
        for (int i = 1; i <= n; i++)
            mem[i] = n - i + 1;
        top = n;
    }
    int new_node() {
        int tmp = mem[top--];
        lc[tmp] = rc[tmp] = 0;
        sum[tmp] = 0;
        return tmp;
    }
    void recycle(int x) {
        mem[++top] = x;
    }
    void dfs(int x) {
        if (lc[x]) dfs(lc[x]);
        if (rc[x]) dfs(rc[x]);
        recycle(x);
    }
    void clear(int x) {
        if (root[x]) dfs(root[x]);
        root[x] = 0;
    }
    void modify(int &root, int l, int r, int pos, int delta) {
        if (root == 0) root = new_node();
        sum[root] += delta;
        if (l == r) return;
        int mid = (l + r) / 2;
        if (mid >= pos) modify(lc[root], l, mid, pos, delta);
        else modify(rc[root], mid + 1, r, pos, delta);
    }
    void modify(int x, int v, int d) {
        modify(root[x], 0, MAXV, v, d);
    }
    int query(int k, int len, int *type, int *home) {
        int l = 0, r = MAXV;
        for (int i = 1; i <= len; i++)
            home[i] = root[home[i]];
        while (l < r) {
            int mid = (l + r) / 2;
            int tsum = 0;
            for (int i = 1; i <= len; i++)
                tsum += type[i] * sum[lc[home[i]]];
            if (tsum >= k) {
                r = mid;
                for (int i = 1; i <= len; i++)
                    home[i] = lc[home[i]];
            } else {
                l = mid + 1;
                k -= tsum;
                for (int i = 1; i <= len; i++)
                    home[i] = rc[home[i]];
            }
        }
        return l;
    }
} SMT;
struct Scapegoat_Tree {
    int root, reroot;
    int len, tindex[MAXN];
    int type[MAXN], home[MAXN];
    int top, mem[MAXN];
    int lc[MAXN], rc[MAXN];
    int index[MAXN], size[MAXN];
    void init(int n) {
        for (int i = 1; i <= n; i++)
            mem[i] = n - i + 1;
        top = n;
    }
    int new_node() {
        int tmp = mem[top--];
        lc[tmp] = rc[tmp] = 0;
        index[tmp] = 0;
        size[tmp] = 0;
        SMT.clear(tmp);
        return tmp;
    }
    void recycle(int x) {
        mem[++top] = x;
    }
    void update(int x) {
        size[x] = 1;
        size[x] += size[lc[x]];
        size[x] += size[rc[x]];
    }
    void dfs(int root) {
        if (root != reroot) recycle(root);
        if (lc[root]) dfs(lc[root]);
        tindex[++len] = index[root];
        if (rc[root]) dfs(rc[root]);
    }
    void rebuild(int root, int l, int r) {
        for (int i = l; i <= r; i++)
            SMT.modify(root, tindex[i], 1);
        int mid = (l + r) / 2;
        index[root] = tindex[mid];
        if (mid > l) {
            lc[root] = new_node();
            rebuild(lc[root], l, mid - 1);
        }
        if (mid < r) {
            rc[root] = new_node();
            rebuild(rc[root], mid + 1, r);
        }
        update(root);
    }
    void rebuild(int root) {
        len = 0;
        dfs(root);
        lc[root] = rc[root] = 0;
        index[root] = size[root] = 0;
        SMT.clear(root);
        rebuild(root, 1, len);
    }
    void index_init(int n, int *a) {
        for (int i = 1; i <= n; i++)
            tindex[i] = a[i];
        root = new_node();
        rebuild(root, 1, n);
    }
    bool unbalance(int root) {
        return max(size[lc[root]], size[rc[root]]) > size[root] * ALPHA + 1;
    }
    void insert(int &root, int pos, int value) {
        if (root == 0) {
            root = new_node();
            index[root] = value;
            size[root] = 1;
            SMT.modify(root, value, 1);
            return;
        }
        SMT.modify(root, value, 1); size[root]++;
        if (pos <= size[lc[root]] + 1) insert(lc[root], pos, value);
        else insert(rc[root], pos - size[lc[root]] - 1, value);
        if (unbalance(root)) reroot = root;
    }
    void insert(int pos, int value) {
        reroot = 0;
        insert(root, pos, value);
        if (reroot) rebuild(reroot);
    }
    int modify(int root, int pos, int value) { /*Return Value: Old Index*/
        SMT.modify(root, value, 1);
        if (pos <= size[lc[root]]) {
            int tmp = modify(lc[root], pos, value);
            SMT.modify(root, tmp, -1);
            return tmp;
        } else {
            pos -= size[lc[root]];
            if (pos == 1) {
                int tmp = index[root];
                index[root] = value;
                SMT.modify(root, tmp, -1);
                return tmp;
            }
            int tmp = modify(rc[root], pos - 1, value);
            SMT.modify(root, tmp, -1);
            return tmp;
        }
    }
    void modify(int pos, int value) {
        modify(root, pos, value);
    }
    void getquery(int root, int l, int r, int t) {
        int mid = size[lc[root]] + 1;
        if (mid > r) getquery(lc[root], l, r, t);
        else if (mid < l) getquery(rc[root], l - mid, r - mid, t);
        else {
            len++; home[len] = root; type[len] = t;
            if (l != 1) getquery(lc[root], 1, l - 1, -t);
            if (r != size[root]) getquery(rc[root], r - size[lc[root]], size[root] - size[lc[root]] - 1, -t);
        }
    }
    int query(int l, int r, int k) {
        len = 0;
        getquery(root, l, r, 1);
        return SMT.query(k, len, type, home);
    }
} SGT;
int num[MAXN];
int main() {
    SMT.init(MAXP - 1);
    SGT.init(MAXN - 1);
    int lastans = 0;
    int n; read(n);
    for (int i = 1; i <= n; i++)
        read(num[i]);
    SGT.index_init(n, num);
    int m; read(m);
    for (int i = 1; i <= m; i++) {
        char opt; int l, r, v;
        getopt(opt);
        if (opt == 'I') {
            read(l), read(v);
            l ^= lastans;
            v ^= lastans;
            SGT.insert(l, v);
        }
        if (opt == 'Q') {
            read(l), read(r), read(v);
            l ^= lastans;
            r ^= lastans;
            v ^= lastans;
            printf("%d\n", lastans = SGT.query(l, r, v));
        }
        if (opt == 'M') {
            read(l), read(v);
            l ^= lastans;
            v ^= lastans;
            SGT.modify(l, v);
        }
    }
    return 0;
} 
  • 平衡树

#include <cstdio>
#include <cstdlib>
#include <ctime>
#define N 500005
using namespace std;
int inline read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int ch[N][2],val[N],pri[N],siz[N],sz;
void update(int x){siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];}
int new_node(int v)
{
siz[++sz]=1;
val[sz]=v;
pri[sz]=rand();
return sz;
}
int merge(int x,int y)
{
if (!x || !y) return x+y;
if (pri[x]<pri[y])
{
ch[x][1]=merge(ch[x][1],y);
update(x);
return x;
}
else
{
ch[y][0]=merge(x,ch[y][0]);
update(y);
return y;
}
}
void split(int now,int k,int &x,int &y)
{
if (!now) x=y=0;
else
{
if (val[now]<=k)
x=now,split(ch[now][1],k,ch[now][1],y);
else
y=now,split(ch[now][0],k,x,ch[now][0]);
update(now);
}
}
int kth(int now,int k)
{
while(1)
{
if (k<=siz[ch[now][0]])
now=ch[now][0];
else
if (k==siz[ch[now][0]]+1)
return now;
else
k-=siz[ch[now][0]]+1,now=ch[now][1];
}
}
main()
{
srand((unsigned)time(NULL));
int T,com,x,y,z,a,b,root=0;
scanf("%d",&T);
while(T--)
{
com=read(),a=read();
if (com==1)
{
split(root,a,x,y);
root=merge(merge(x,new_node(a)),y);
}
else
if (com==2)
{
split(root,a,x,z);
split(x,a-1,x,y);
y=merge(ch[y][0],ch[y][1]);
root=merge(merge(x,y),z);
}
else
if (com==3)
{
split(root,a-1,x,y);
printf("%d\n",siz[x]+1);
root=merge(x,y);
}
else
if (com==4)
printf("%d\n",val[kth(root,a)]);
else
if (com==5)
{
split(root,a-1,x,y);
printf("%d\n",val[kth(x,siz[x])]);
root=merge(x,y);
}
else
{
split(root,a,x,y);
printf("%d\n",val[kth(y,1)]);
root=merge(x,y);
}
}
}
//fhq treap
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<ctime>
#include<algorithm>

using namespace std;

int root,n,a,b,tmp;
int sz;
struct treap {
    int sz,tot,w,rnd,ch[2];
    int lc,rc;
} t[1000500];

void update(int x) {
    t[x].sz=t[t[x].ch[0]].sz+t[t[x].ch[1]].sz+t[x].tot;
}

void turn(int &x,int k) {
    int y=t[x].ch[k^1];
    t[x].ch[k^1]=t[y].ch[k];
    t[y].ch[k]=x;
    update(x);
    update(y);
    x=y;
}

void insert(int &x,int w) {
    if(!x) {
        t[++sz].w=w;
        t[sz].rnd=rand();
        t[sz].tot=t[sz].sz=1;
        x=sz;
    } else {
        if(t[x].sz++,t[x].w==w)t[x].tot++;

        else if(insert(t[x].ch[tmp=w>t[x].w],w),t[t[x].ch[tmp]].rnd>t[x].rnd) {
            turn(x,tmp^1);
        }
    }
}

void del(int &x,int w) {
    if(!x)return;
    if(t[x].w==w) {
        if(t[x].tot>1)t[x].tot--,t[x].sz--;
        else {
            if(!(t[x].ch[0]&&t[x].ch[1]))x=t[x].ch[0]|t[x].ch[1];
            else
                turn(x,tmp=t[t[x].ch[0]].rnd>t[t[x].ch[1]].rnd),t[x].sz--,del(t[x].ch[tmp],w);
        }
    } else t[x].sz--,del(t[x].ch[w>t[x].w],w);
}

int rank1(int x,int w) {
    if(t[x].w==w)return t[t[x].ch[0]].sz+1;
    if(t[x].w<w)return t[t[x].ch[0]].sz+t[x].tot+rank1(t[x].ch[1],w);
    else return rank1(t[x].ch[0],w);
}

int kth(int x,int w) {
    if(!x)return 0;
    if(w<=t[t[x].ch[0]].sz)return kth(t[x].ch[0],w);
    else if(w>t[t[x].ch[0]].sz+t[x].tot)return kth(t[x].ch[1],w-t[t[x].ch[0]].sz-t[x].tot);
    else return t[x].w;
}

int pre(int v) {
    insert(root,v);
    tmp=kth(root,rank1(root,v)-1);
    del(root,v);
    return tmp;
}

int find(int x,int v) {
    return t[x].w==v?x:find(t[x].ch[t[x].w<v],v);
}

int sub(int v) {
    insert(root,v);
    tmp=kth(root,rank1(root,v)+t[find(root,v)].tot);
    del(root,v);
    return tmp;
}

int main() {

    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        scanf("%d%d",&a,&b);
        if(a==1)insert(root,b);
        if(a==2)del(root,b);
        if(a==3)printf("%d\n",rank1(root,b));
        if(a==4)printf("%d\n",kth(root,b));
        if(a==5)printf("%d\n",pre(b));
        if(a==6)printf("%d\n",sub(b));
    }
}
//treap
#include<cstdio>
struct SBT {
    int v, sz, ch[2], cnt;
} t[300005];
int n, cnt, root;
#define Upd(k) {\
    t[k].sz = t[t[k].ch[0]].sz + t[t[k].ch[1]].sz + t[k].cnt;\
}
void rot(int &k, bool f) {
    int p = t[k].ch[f]; t[k].ch[f] = t[p].ch[!f]; t[p].ch[!f] = k;
    Upd(k); Upd(p); k = p;
}
inline void mt(int &k,bool f)
{
    if(!k) return;
    if(t[t[k].ch[f^1]].sz < t[t[t[k].ch[f]].ch[f]].sz) rot(k, f);
    else if(t[t[k].ch[f^1]].sz < t[t[t[k].ch[f]].ch[f^1]].sz) { rot(t[k].ch[f], f^1); rot(k, f); }
    else return;
    mt(t[k].ch[f],f);
    mt(k,f);
}
void Ins(int &k, int x) {
    if(!k) {k = ++ cnt; t[k].sz = t[k].cnt = 1; t[k].v = x; return; }
    ++ t[k].sz;
    if(t[k].v == x) {++ t[k].cnt; return;}
    Ins(t[k].ch[t[k].v < x], x);
    mt(k, t[k].v < x);
}
int Del(int &k, int x) {
    if(!k) return k;
    int tmp;
    if(t[k].v == x) {
        if(t[k].cnt > 1) {-- t[k].cnt; --t[k].sz; return k;}
        else if(!(t[k].ch[0]*t[k].ch[1])) {k = t[k].ch[0]+t[k].ch[1];}
        else { tmp = Del(t[k].ch[0], x+1); t[k].cnt = t[tmp].cnt; t[k].v = t[tmp].v; Upd(k); return k; }
    }
    else if((t[k].v < x && !t[k].ch[1]) || (t[k].v > x && ! t[k].ch[0])) { tmp = k; k = t[k].ch[0]; Upd(k); return tmp; }
    else tmp = Del(t[k].ch[t[k].v < x], x);
    Upd(k); return tmp;
}
int Ran(int k,int x) {
    if(k==0)return 0;
    if(t[k].v==x)return t[t[k].ch[0]].sz+1;
    else if(x>t[k].v)
        return t[t[k].ch[0]].sz+t[k].cnt+Ran(t[k].ch[1],x);
    else return Ran(t[k].ch[0],x);
}
int Kth(int k,int x) {
    if(k==0)return 0;
    if(x<=t[t[k].ch[0]].sz)
        return Kth(t[k].ch[0],x);
    else if(x>t[t[k].ch[0]].sz+t[k].cnt)
        return Kth(t[k].ch[1],x-t[t[k].ch[0]].sz-t[k].cnt);
    else return t[k].v;
}
int ans;
void pred(int k,int x) {
    if(k==0)return;
    if(t[k].v<x) {
        ans=k;
        pred(t[k].ch[1],x);
    } else pred(t[k].ch[0],x);
}
void succ(int k,int x) {
    if(k==0)return;
    if(t[k].v>x) {
        ans=k;
        succ(t[k].ch[0],x);
    } else succ(t[k].ch[1],x);
}
char c, f;
inline void GET(int &n) {
    n = 0; f = 1;
    do {c = getchar(); if(c == '-') f = -1;} while(c > '9' || c < '0');
    while(c >= '0' && c <= '9') {n=n*10+c-'0';c=getchar();}
    n *= f;
}
int main() {
    GET(n);
    int opt,x;
    for(int i=1; i<=n; i++) {
        GET(opt); GET(x);
        switch(opt) {
            case 1: Ins(root,x); break;
            case 2: Del(root,x); break;
            case 3: printf("%d\n",Ran(root,x)); break;
            case 4: printf("%d\n",Kth(root,x)); break;
            case 5: ans=0; pred(root,x); printf("%d\n",t[ans].v); break;
            case 6: ans=0; succ(root,x); printf("%d\n",t[ans].v); break;
        }
    }
    return 0;
}
//SBT
#include <cstdio>
#define Maxn 1000000
using namespace std;
int f[Maxn];//father
int ch[Maxn][2];//child ; 0 for left ; 1 for right
int key[Maxn];//key
int cnt[Maxn];//value
int siz[Maxn];//size of subtree
int sz,root;//size of tree and root
//clear the ndoe
void clear(int x)
{
    ch[x][0]=ch[x][1]=f[x]=cnt[x]=key[x]=siz[x]=0;
}
//rightson return 1;left son return 0
int getson(int x)
{
    return ch[f[x]][1]==x;
}
//update the size
void update(int x)
{
    siz[x]=cnt[x];
    if (ch[x][0]) siz[x]+=siz[ch[x][0]];
    if (ch[x][1]) siz[x]+=siz[ch[x][1]];
}
//retation
int rotate(int x)
{
    int fa=f[x],fafa=f[fa],k=getson(x);
    ch[fa][k]=ch[x][k^1];f[ch[fa][k]]=fa;
    ch[x][k^1]=fa;f[fa]=x;
    f[x]=fafa;
    if (fafa)
        ch[fafa][ch[fafa][1]==fa]=x;
    update(fa);update(x);
}
//rotate until x is the root
void splay(int x)
{
    for (int fa;fa=f[x];rotate(x))
        if (f[fa])
            rotate(getson(x)==getson(fa) ? fa : x);
    root=x;
}
int pre()
{
    int now=ch[root][0];
    while(ch[now][1])
        now=ch[now][1];
    return now;
}
int nex()
{
    int now=ch[root][1];
    while(ch[now][0])
        now=ch[now][0];
    return now;
}
//find x's pos
int findpos(int v)
{
    int now=root,ans=0;
    while(1)
    {
        if (v<key[now])
            now=ch[now][0];
        else
        {
            ans+=ch[now][0]?siz[ch[now][0]]:0;
            if (v==key[now]) 
            {
                splay(now);
                return ans+1;
            }
            ans+=cnt[now];
            now=ch[now][1];
        }
    }
}
//find pos's x
int findx(int x)
{
    int now=root;
    while(1)
    {
        if (ch[now][0] && x<=siz[ch[now][0]])
            now=ch[now][0];
        else
        {
            int temp=(ch[now][0]?siz[ch[now][0]]:0)+cnt[now];
            if (x<=temp)
                return key[now];
            x-=temp;
            now=ch[now][1];
        }
    }
}
//ceate a new splay node
void create(int v)
{
    sz++;
    ch[sz][0]=ch[sz][1]=f[sz]=0;
    key[sz]=v;
    cnt[sz]=1;
    siz[sz]=1;
    //root=sz;
}
//insert a node
void insert(int v)
{
    if (!root)
        create(v),root=sz;
    else
    {
        int now=root,fa=0;
        while(1)
        {
            if (key[now]==v)
            {
                cnt[now]++;
                update(now);update(fa);
                splay(now);
                break;
            }
            fa=now;
            now=ch[fa][v>key[fa]];
            if (!now)
            {
                create(v);
                f[sz]=fa;
                ch[fa][v>key[fa]]=sz;
                update(fa);
                splay(sz);
                break;
            }
        }
    }
}
void del(int x)
{
    int t=findpos(x);
    if (cnt[root]>1) 
    {
        cnt[root]--;
        update(root);
        return;
    }
    //none
    if (!ch[root][0] && !ch[root][1])
    {
        clear(root);
        root=0;
        return;
    }
    //one
    if (!ch[root][1])
    {
        int temp=root;
        root=ch[root][0];
        f[root]=0;
        clear(temp);
        return;
    }
    else
    if (!ch[root][0])
    {
        int temp=root;
        root=ch[root][1];
        f[root]=0;
        clear(temp);
        return;
    }
    //two
    int pre1=pre(),temp=root;
    splay(pre1);
    f[ch[temp][1]]=root;
    ch[root][1]=ch[temp][1];
    clear(temp);
    update(root);
}
int main()
{  
    int n,opt,x;  
    scanf("%d",&n);  
    for (int i=1;i<=n;++i)
    {  
        scanf("%d%d",&opt,&x);  
        switch(opt)
        {  
            case 1: insert(x); break;  
            case 2: del(x); break;  
            case 3: printf("%d\n",findpos(x)); break;  
            case 4: printf("%d\n",findx(x)); break;  
            case 5: insert(x); printf("%d\n",key[pre()]); del(x); break;
            case 6: insert(x); printf("%d\n",key[nex()]); del(x); break;
        }  
    }  
}
//splay
#include<cstdio>
#include<algorithm>
using namespace std;
const double r=0.78;
const int maxn=100010,oo=0x3f3f3f3f;
int rd()
{
    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*10+c-'0';
        c=getchar();
    }
    return x*f;
}
int son[maxn][2],siz[maxn],num[maxn],w[maxn],cnt[maxn],
fid[maxn],fw[maxn],fcnt[maxn],sta[maxn],
tot,clo,rt,id,fa,b;
void pause()
{
    int x;
    x=1;
}
void upd(int u)
{
    if (!u) return;
    siz[u]=siz[son[u][0]]+siz[son[u][1]]+1;
    num[u]=num[son[u][0]]+num[son[u][1]]+cnt[u];
}
void check(int u)
{
    if (!u) return;
    if (siz[son[u][0]]>siz[u]*r||siz[son[u][1]]>siz[u]*r)
        id=u,fa=-1;
    if (son[u][0]==id)
    {
        fa=u;
        b=0;
    }
    if (son[u][1]==id)
    {
        fa=u;
        b=1;
    }
}
void dfs(int u)
{
    if (!u) return;
    dfs(son[u][0]);
    clo++;
    fid[clo]=u;
    fw[clo]=w[u];
    fcnt[clo]=cnt[u];
    dfs(son[u][1]);
}
int build(int L,int R)
{
    if (L>R) return 0;
    int mid=L+R>>1,u;
    u=fid[mid];
    w[u]=fw[mid];
    cnt[u]=fcnt[mid];
    son[u][0]=build(L,mid-1);
    son[u][1]=build(mid+1,R);
    upd(u);
    return u;
}
int solve(int u)
{
    /*if (siz[son[u][0]]==-1) pause();
    printf("%d:%dvs%d\n",siz[u],siz[son[u][0]],siz[son[u][1]]);*/
    clo=0;
    dfs(u);
    return build(1,clo);
}
int ins(int u,int x)
{
    if (!u)
    {
        u=++tot;
        w[u]=x;
        cnt[u]=siz[u]=num[u]=1;
        return u;
    }
    if (w[u]==x)
    {
        cnt[u]++;
        num[u]++;
        return u;
    }
    son[u][x>w[u]]=ins(son[u][x>w[u]],x);
    upd(u);
    check(u);
    return u;
}
int del(int u,int x)
{
    //if (x==-8195776) pause();
    if (x==w[u])
    {
        cnt[u]--;
        if (!cnt[u])
        {
            if (son[u][0]*son[u][1]==0) u=son[u][0]+son[u][1];
            else
            {
                int fl=siz[son[u][0]]<siz[son[u][1]];
                int p=son[u][fl],top=0;
                while (son[p][fl^1]) sta[++top]=p,p=son[p][fl^1];
                if (top)
                {
                    son[sta[top]][fl^1]=son[p][fl];
                    son[p][0]=son[u][0];
                    son[p][1]=son[u][1];
                    for (;top;top--) upd(sta[top]);
                }
                else son[p][fl^1]=son[u][fl^1];
                u=p;
            }
        }
        upd(u);
        check(u);
        return u;
    }
    son[u][x>w[u]]=del(son[u][x>w[u]],x);
    upd(u);
    check(u);
    return u;
}
int get_rank(int u,int x)
{
    if (!u) return 0;
    if (x==w[u]) return num[son[u][0]]+1;
    if (x<w[u]) return get_rank(son[u][0],x);
    return cnt[u]+num[son[u][0]]+get_rank(son[u][1],x);
}
int qry(int u,int x)
{
    if (x<=num[son[u][0]]) return qry(son[u][0],x);
    if (x<=cnt[u]+num[son[u][0]]) return w[u];
    return qry(son[u][1],x-(cnt[u]+num[son[u][0]]));
}
int pre(int u,int x)
{
    if (!u) return -oo;
    if (w[u]>=x) return pre(son[u][0],x);
    return max(w[u],pre(son[u][1],x));
}
int succ(int u,int x)
{
    if (!u) return oo;
    if (w[u]<=x) return succ(son[u][1],x);
    return min(w[u],succ(son[u][0],x));
}
int main()
{
    /*freopen("phs.in","r",stdin);
    freopen("phs.out","w",stdout);*/
    int n,opt;
    n=rd();
    while (n--)
    {
        /*if (n%3000==0) printf("%d\n",n);
        if (n%5000==0) pause();*/
        opt=rd();
        switch (opt)
        {
            case 1:
                id=-1;
                rt=ins(rt,rd());
                if (id>0)
                {
                    if (fa==-1) rt=solve(id);
                    else son[fa][b]=solve(id);
                }
                break;
            case 2:
                id=-1;
                rt=del(rt,rd());
                if (id>0)
                {
                    if (fa==-1) rt=solve(id);
                    else son[fa][b]=solve(id);
                }
                break;
            //default:rd();break;
            case 3:printf("%d\n",get_rank(rt,rd()));break;
            case 4:printf("%d\n",qry(rt,rd()));break;
            case 5:printf("%d\n",pre(rt,rd()));break;
            case 6:printf("%d\n",succ(rt,rd()));break;
            /*case 3:get_rank8(rt,rd());break;
            case 4:qry(rt,rd());break;
            case 5:pre(rt,rd());break;
            case 6:succ(rt,rd());break;*/
        }
    }
}
//SGT
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<ctime>
using namespace std;
const int N=5e5+10;
int n,rt[N],cnt;

struct Node{
    int ch[2];
    int rnd,sz,v;
}t[N*50];

inline int read()
{
    int x=0,t=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*t;
}

inline int copynode(int x)
{
    t[++cnt]=t[x];
    return cnt;
}
inline int newnode(int x)
{
   t[++cnt].v=x;t[cnt].sz=1;t[cnt].rnd=rand();
   return cnt;
}
inline void update(int k)
{
    if(k)
    t[k].sz=t[t[k].ch[0]].sz+t[t[k].ch[1]].sz+1;
}

inline void split(int now,int k,int &x,int &y)
{
    if(!now) {x=0;y=0;return;}
    if(t[now].v<=k){
        x=copynode(now);
        split(t[x].ch[1],k,t[x].ch[1],y);
    }else{
        y=copynode(now);
        split(t[y].ch[0],k,x,t[y].ch[0]);
    }
    update(x);update(y);
}
inline int merge(int x,int y)
{
    if(!x || !y) return x+y;
    if(t[x].rnd<t[y].rnd){
        int z=copynode(x);
        t[z].ch[1]=merge(t[z].ch[1],y);
        update(z);
        return z;
    }else{
        int z=copynode(y);
        t[z].ch[0]=merge(x,t[z].ch[0]); 
        update(z);
        return z;
    }
}
inline void insert(int now,int k)
{
    int x=0,y=0,z=0;
    split(rt[now],k,x,y);
    z=newnode(k);
    rt[now]=merge(merge(x,z),y);
}

inline void del(int now,int k)
{
    int x=0,y=0,z=0;
    split(rt[now],k,x,y);
    split(x,k-1,x,z);
    z=merge(t[z].ch[0],t[z].ch[1]);
    rt[now]=merge(merge(x,z),y);
}

inline int rnk(int now,int k)
{
    int x=0,y=0;
    split(rt[now],k-1,x,y);
    return t[x].sz+1;
}

inline int kth(int x,int k)
{
   while(1){
      if(t[t[x].ch[0]].sz+1 ==k) return t[x].v;
      else if(t[t[x].ch[0]].sz>=k) x=t[x].ch[0];
      else {k-=(t[t[x].ch[0]].sz+1);x=t[x].ch[1];}
      //1-> cause the same are not on the same
   }
}
inline int pre(int now,int k)
{
   int x=0,y=0,z=0;
   split(rt[now],k-1,x,y);
   if(!x) return -2147483647;
   return kth(x,t[x].sz);
}

inline int suf(int now,int k)
{
    int x=0,y=0,z=0;
    split(rt[now],k,x,y);
    if(!y) return 2147483647;
    return kth(y,1);
}

int main(){
    srand(time(0));
    n=read();
    for(int i=1;i<=n;i++){
        int in=read(),op=read();
        rt[i]=rt[in];
        if(op==1) insert(i,read());
        else 
        if(op==2) del(i,read());
        else 
        if(op==3) printf("%d\n",rnk(i,read()));
        else 
        if(op==4) printf("%d\n",kth(rt[i],read()));
        else 
        if(op==5) printf("%d\n",pre(i,read()));
        else  
        printf("%d\n",suf(i,read()));
    }
    return 0;
}
//可持久化平衡树 
  • 并查集

#include<iostream>
#include<cstdio>
using namespace std;
int f[2000010];
int find(int x)
{
    return x==f[x]?x:f[x]=find(f[x]);
}

void merge(int a,int b){
    int f1=find(a),f2=find(b);
    if(f1!=f2){
        f[f2]=f1;
    }
}

int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) f[i]=i;
    while(m--){
        int opt;
        cin>>opt;
        switch(opt){
            case(1):{
                int a,b;
                cin>>a>>b;
                merge(a,b);
                break;
            }
            case(2):{
                int a,b;
                cin>>a>>b;
                if(find(a)==find(b)){
                    cout<<"Y"<<endl;
                }
                else cout<<"N"<<endl;
            }
        }
    }
}
#include<cstdio>
#include<iostream>
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
int n,m,sz,last;
int root[200005],ls[10000005],rs[10000005],v[10000005],deep[10000005];
void build(int &k,int l,int r)
{
    if(!k)k=++sz;
    if(l==r){v[k]=l;return;}
    int mid=(l+r)>>1;
    build(ls[k],l,mid);
    build(rs[k],mid+1,r);
}
void modify(int l,int r,int x,int &y,int pos,int val)
{
    y=++sz;
    if(l==r){v[y]=val;return;}
    ls[y]=ls[x];rs[y]=rs[x];
    int mid=(l+r)>>1;
    if(pos<=mid)
        modify(l,mid,ls[x],ls[y],pos,val);
    else modify(mid+1,r,rs[x],rs[y],pos,val);
}
int query(int k,int l,int r,int pos)
{
    if(l==r)return k;
    int mid=(l+r)>>1;
    if(pos<=mid)return query(ls[k],l,mid,pos);
    else return query(rs[k],mid+1,r,pos);
}
void add(int k,int l,int r,int pos)
{
    if(l==r){deep[k]++;return;}
    int mid=(l+r)>>1;
    if(pos<=mid)add(ls[k],l,mid,pos);
    else add(rs[k],mid+1,r,pos);
}
int find(int k,int x)
{
    int p=query(k,1,n,x);
    if(x==v[p])return p;
    return find(k,v[p]);
}
int main()
{
    n=read();m=read();
    build(root[0],1,n);
    int f,k,a,b;
    for(int i=1;i<=m;i++)
    {
        f=read();
        if(f==1)
        {
            root[i]=root[i-1];
            a=read();b=read();a=a^last;b=b^last;
            int p=find(root[i],a),q=find(root[i],b);
            if(v[p]==v[q])continue;
            if(deep[p]>deep[q])swap(p,q);
            modify(1,n,root[i-1],root[i],v[p],v[q]);
            if(deep[p]==deep[q])add(root[i],1,n,v[q]);
        }
        if(f==2)
        {k=read();k=k^last;root[i]=root[k];}
        if(f==3)
        {
            root[i]=root[i-1];
            a=read();b=read();a=a^last;b=b^last;
            int p=find(root[i],a),q=find(root[i],b);
            if(v[p]==v[q])last=1;
            else last=0;
            printf("%d\n",last);
        }
    }
    return 0;
}
//好吧其实可持久并查集和并查集并没什么太大关系,主席树维护持久数组
//留坑二维并查集
  • 树链剖分

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct tree{int l,r,sum,book;}tr[400005];
struct edge{int to,nxt;}e[200005];
int head[100005],tot,cnt;
int p[100005],y[100005],x[100005],si[100005];
int dep[100005],fa[100005],bl[100005];
int n,m,ans,mod,root;
void add(int u,int v){e[++tot].to=v;e[tot].nxt=head[u];head[u]=tot;}
void dfs(int u){
    si[u]=1;
    for(int v,c=head[u];c;c=e[c].nxt){
        v=e[c].to;
        if(v==fa[u])continue;
        dep[v]=dep[u]+1;fa[v]=u;
        dfs(v);
        si[u]+=si[v];
    }
}
void dfs2(int u,int blo){
    p[u]=++cnt;bl[u]=blo;y[p[u]]=x[u];
    int k=0;
    for(int v,c=head[u];c;c=e[c].nxt){
        v=e[c].to;
        if(dep[v]!=dep[u]+1)continue;
        if(si[v]>si[k])k=v;
    }
    if(k==0)return;
    dfs2(k,blo);
    for(int v,c=head[u];c;c=e[c].nxt){
        if(e[c].to==k)continue;
        v=e[c].to;
        if(dep[v]!=dep[u]+1)continue;
        dfs2(v,v);
    }
}
void pushdown(int now){
    tr[now*2].book=(tr[now].book+tr[now*2].book)%mod;
    tr[now*2+1].book=(tr[now].book+tr[now*2+1].book)%mod;
    tr[now].sum=(tr[now].sum+(tr[now].r-tr[now].l+1)*tr[now].book%mod)%mod;
    tr[now].book=0;
}
void tr_build(int l,int r,int now){
    tr[now].l=l;tr[now].r=r;
    if(l==r){
        tr[now].sum=y[l];
        return ;
    }
    else{
        int mid=(l+r)/2;
        tr_build(l,mid,now*2);
        tr_build(mid+1,r,now*2+1);
        tr[now].sum=tr[now*2].sum+tr[now*2+1].sum;
    }
}
void bt_add(int l,int r,int c,int now){
    if(l==tr[now].l&&r==tr[now].r){
        if(l==r)tr[now].sum=(tr[now].sum+c)%mod;
        else tr[now].book=(tr[now].book+c)%mod;
        return;
    }
    tr[now].sum=(tr[now].sum+(r-l+1)*c%mod)%mod;
    int mid=(tr[now].l+tr[now].r)/2;
    if(l>mid)bt_add(l,r,c,now*2+1);
    else if(r<=mid)bt_add(l,r,c,now*2);
    else{
        bt_add(l,mid,c,now*2);
        bt_add(mid+1,r,c,now*2+1);
    }
}
void bt_ser(int l,int r,int now){
    if(l==tr[now].l&&r==tr[now].r){
        ans=(ans+tr[now].sum+(r-l+1)*tr[now].book%mod)%mod;
        return;
    }
    pushdown(now);
    int mid=(tr[now].l+tr[now].r)/2;
    if(l>mid)bt_ser(l,r,now*2+1);
    else if(r<=mid)bt_ser(l,r,now*2);
    else{
        bt_ser(l,mid,now*2);
        bt_ser(mid+1,r,now*2+1);
    }
}
void si_add(int u,int v,int s){
    while(bl[u]!=bl[v]){
        if(dep[bl[u]]>dep[bl[v]])swap(u,v);
        bt_add(p[bl[v]],p[v],s,1);
        v=fa[bl[v]];
    }
    if(dep[u]>dep[v])swap(u,v);
    bt_add(p[u],p[v],s,1);
}
void si_sum(int u,int v){
    ans=0;
    while(bl[u]!=bl[v]){
        if(dep[bl[u]]>dep[bl[v]])swap(u,v);
        bt_ser(p[bl[v]],p[v],1);
        v=fa[bl[v]];
    }
    if(dep[u]>dep[v])swap(u,v);
    bt_ser(p[u],p[v],1);
    printf("%d\n",ans);
}
void tr_add(int u,int s){bt_add(p[u],p[u]+si[u]-1,s,1);}
void tr_sum(int u){
    ans=0;
    bt_ser(p[u],p[u]+si[u]-1,1);
    printf("%d\n",ans);
}
int main(){
    scanf("%d%d%d%d",&n,&m,&root,&mod);
    for(int i=1;i<=n;++i)scanf("%d",&x[i]); 
    for(int i=1,u,v;i<n;++i){
        scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    dfs(root);dfs2(root,root);
    tr_build(1,n,1);
    for(int i=1,opt,u,v,s;i<=m;++i){
        scanf("%d%d",&opt,&u);
        if(opt==1){
            scanf("%d%d",&v,&s);
            si_add(u,v,s%mod);
        }
        else if(opt==2){
            scanf("%d",&v);
            si_sum(u,v);
        }
        else if(opt==3){
            scanf("%d",&s);
            tr_add(u,s%mod);
        }
        else {tr_sum(u);}
    }
    return 0;
}
  • 树状数组

懒得写了

  • 动态树

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=300005;
int n,m,top;
int ch[maxn][2],rev[maxn],que[maxn];
int fa[maxn],val[maxn],sum[maxn];
bool isroot(int x){
    return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
}
void pushup(int x){
    sum[x]=sum[ch[x][0]]^val[x]^sum[ch[x][1]];
}
void pushdown(int x){
    if(rev[x]){
        rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
        rev[x]=0;
    }
}
void rotat(int x){
    int y=fa[x],z=fa[y],l,r;
    if(ch[y][0]==x)l=0;else l=1;r=l^1;
    if(!isroot(y)){
        ch[z][ch[z][1]==y]=x;
    }
    fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
    ch[y][l]=ch[x][r];ch[x][r]=y;
    pushup(y);pushup(x);
}
void splay(int x){
    int i;
    for(i=x;!isroot(i);i=fa[i]){
        que[++top]=i;
    }
    que[++top]=i;
    while(top)pushdown(que[top--]);
    while(!isroot(x)){
        int y=fa[x],z=fa[y];
        if(!isroot(y)){
            if((ch[z][0]==y)^(ch[y][0]==x))rotat(x);
            else rotat(y);
        }
        rotat(x);
    }
}
void access(int x){
    int lst=0;
    while(x){
        splay(x);ch[x][1]=lst;pushup(x);lst=x;x=fa[x];
    }
}
void makeroot(int x){
    access(x);splay(x);rev[x]^=1;
}
void link(int x,int y){
    makeroot(x);fa[x]=y;pushup(y);
}
void cut(int x,int y){
    makeroot(x);access(y);splay(y);
    if(ch[y][0]==x){
        ch[y][0]=fa[x]=0;pushup(y);
    }
}
void change(int x,int y){
    access(x);splay(x);val[x]=y;pushup(x);
}
int LCT_query(int x,int y){
    makeroot(x);access(y);splay(y);
    return sum[y];
}
int findroot(int x){
    access(x);splay(x);
    while(ch[x][0])x=ch[x][0];
    return x;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        scanf("%d",&val[i]);
    int opt,x,y;
    for(int i=1;i<=m;++i){
        scanf("%d%d%d",&opt,&x,&y);
        switch(opt){
            case 0:{
                printf("%d\n",LCT_query(x,y));
                break;
            }
            case 1:{
                if(findroot(x)!=findroot(y))
                    link(x,y);
                break;
            }
            case 2:{
                cut(x,y);
                break;
            }
            case 3:{
                change(x,y);
                break;
            }
        }
    }
    return 0;
}
  • 点分治

//IOI2011Race
// luogu-judger-enable-o2
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 200010
#define maxk 1000010
#define INF 1000000009
struct edge{
    int to,nxt,w;
}e[maxn<<1];
int n,root,k,sum,head[maxn],tot,tmp[maxk],dis[maxn],dep[maxn],ans=INF,vis[maxn],siz[maxn],g[maxn];
void add(int u,int v,int w){
    e[++tot].to=v;
    e[tot].w=w;
    e[tot].nxt=head[u];
    head[u]=tot;
}
void getroot(int u,int fa){
    siz[u]=1;
    g[u]=0;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v]||v==fa) continue;
        getroot(v,u);
        siz[u]+=siz[v];
        g[u]=max(g[u],siz[v]);
    }
    g[u]=max(g[u],sum-siz[u]);
    if(g[u]<g[root]) root=u;
}
void dfsdis(int u,int fa){
    if(dis[u]<=k) ans=min(ans,tmp[k-dis[u]]+dep[u]);
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v]||v==fa) continue;
        dis[v]=dis[u]+e[i].w;
        dep[v]=dep[u]+1;
        dfsdis(v,u);
    }
}
void calc(int u,int fa,int p){
    if(dis[u]<=k){
        if(p) tmp[dis[u]]=min(tmp[dis[u]],dep[u]);
        else tmp[dis[u]]=INF;
    }
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v]||v==fa) continue;
        calc(v,u,p);
    }
}
void dfs(int u){
    vis[u]=1; tmp[0]=0;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v]) continue;
        dis[v]=e[i].w; dep[v]=1;
        dfsdis(v,0);
        calc(v,0,1);
    }
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v]) continue;
        calc(v,0,0);
    }
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(vis[v]) continue;
        root=0;
        sum=siz[v];
        getroot(v,0);
        dfs(root);
    }
}
int main(){
    scanf("%d %d",&n,&k);
    for(int i=1;i<=k;++i) tmp[i]=INF;
    for(int i=1;i<n;++i){
        int u,v,w;
        scanf("%d %d %d",&u,&v,&w);
        ++u; 
        ++v;
        add(u,v,w); 
        add(v,u,w);
    }
    root=0;
    sum=g[0]=n;
    getroot(1,0);
    dfs(root);
    if(ans!=INF) printf("%d",ans);
    else printf("-1");
    return 0;
}
点分树比点分治就多一个记录重心父亲

Day2结束,华丽的分割线


猜你喜欢

转载自www.cnblogs.com/akoasm/p/9419662.html