BZOJ 2733 线段树的合并 并查集

来源:互联网 发布:ipowerl软件下载 编辑:程序博客网 时间:2024/05/22 21:24

思路:
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\n",tr[root[find(xx)]]<yy?-1:rev[query(root[find(xx)],1,n,yy)]);        else add();    }}

这里写图片描述

0 0
原创粉丝点击