C68 线段树合并+并查集 P3224 [HNOI2012] 永无乡

视频链接:254 线段树合并+并查集 P3224 [HNOI2012] 永无乡_哔哩哔哩_bilibili

 

 

 

Luogu P3224 [HNOI2012] 永无乡

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

void read(int &l){ //快读
  l=0; char c=getchar();
  while(!isdigit(c))c=getchar();
  while(isdigit(c))l=l*10+c-'0',c=getchar();
}
const int N=100005;
#define mid (l+r)/2
int n,m,q,f[N];  //f:并查集
int root[N],tot; //根节点,开点个数
int ls[N*20],rs[N*20],id[N*20],sum[N*20];
//id:节点编号,sum:重要度的出现次数之和

int find(int x){ //找根
  return x==f[x]?x:f[x]=find(f[x]);
}
void pushup(int u){ //上传
  sum[u]=sum[ls[u]]+sum[rs[u]];
}
int change(int u,int l,int r,int p,int i){ //点修
  if(!u) u=++tot;
  if(l==r){id[u]=i; sum[u]++; return u;}
  if(p<=mid) ls[u]=change(ls[u],l,mid,p,i);
  else rs[u]=change(rs[u],mid+1,r,p,i);
  pushup(u); return u;
}
int merge(int x,int y){ //合并
  if(!x||!y) return x+y;
  ls[x]=merge(ls[x],ls[y]);
  rs[x]=merge(rs[x],rs[y]);
  pushup(x); return x;
}
int query(int u,int l,int r,int k){ //点查
  if(l==r) return id[u];
  int ans=0;
  if(k<=sum[ls[u]]) ans=query(ls[u],l,mid,k);
  else ans=query(rs[u],mid+1,r,k-sum[ls[u]]);
  return ans;
}
int main(){
  read(n);read(m); int x,y;
  for(int i=1;i<=n;i++){
    f[i]=i; read(x);
    root[i]=change(root[i],1,n,x,i);
  }
  for(int i=1;i<=m;i++){
    read(x);read(y);x=find(x);y=find(y);
    if(x==y) continue;
    f[y]=x;
    root[x]=merge(root[x],root[y]);
  }
  read(q);
  while(q--){
    char ch[2]; scanf("%s",ch);
    if(ch[0]=='B'){
      read(x);read(y); 
      x=find(x);y=find(y);
      if(x==y) continue;
      f[y]=x;
      root[x]=merge(root[x],root[y]);
    }
    else{
      read(x);read(y); x=find(x);
      int ans=query(root[x],1,n,y);
      ans=ans?ans:-1;
      printf("%d\n",ans);
    }
  }
}

 

posted @ 2023-11-15 22:06  董晓  阅读(179)  评论(0编辑  收藏  举报