BZOJ 2733 线段树的合并 并查集

思路:
1.线段树合并(nlogn的)
2.splay+启发式合并

线段树合并比较好写
我手懒

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100050;
int n,m,q,a[N],f[N],xx,yy,son[N*50][2],tr[N*50],root[N],cnt,rev[N];
char op[10];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void push_up(int x){tr[x]=tr[son[x][0]]+tr[son[x][1]];}
void insert(int &x,int l,int r,int wei){
    if(!x)x=++cnt;
    if(l==r){tr[x]++;return;}
    int mid=(l+r)>>1;
    if(mid<wei)insert(son[x][1],mid+1,r,wei);
    else insert(son[x][0],l,mid,wei); 
    push_up(x);
}
int merge(int x,int y){
    if(!y||!x)return x^y;
    son[x][0]=merge(son[x][0],son[y][0]),
    son[x][1]=merge(son[x][1],son[y][1]);
    push_up(x);return x;
}
int query(int x,int l,int r,int num){
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(tr[son[x][0]]>=num)return query(son[x][0],l,mid,num);
    return query(son[x][1],mid+1,r,num-tr[son[x][0]]);
}
void add(){
    int fx=find(xx),fy=find(yy);
    if(fx!=fy)root[fx]=merge(root[fx],root[fy]),f[fy]=fx; 
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),f[i]=i,insert(root[i],1,n,a[i]),rev[a[i]]=i;
    while(m--)scanf("%d%d",&xx,&yy),add();
    scanf("%d",&q);
    while(q--){
        scanf("%s%d%d",op,&xx,&yy);
        if(op[0]=='Q')printf("%d
",tr[root[find(xx)]]<yy?-1:rev[query(root[find(xx)],1,n,yy)]);
        else add();
    }
}

这里写图片描述

原文地址:https://www.cnblogs.com/SiriusRen/p/6532046.html