BZOJ 2733:永无乡

摘要:http://www.lydsy.com/JudgeOnline/problem.php?id=2733

大意:给出\(n\)个结点的图和一些初始的边,每个节点有一个权值且互不相同,给出\(m\)个操作,每次可以在结点\(u,v\)之间连边,或者询问某个节点所在的连通分量的第\(K\)大结点编号。

解析:对于每个连通分量我们维护一棵Treap,每次查询在Treap里面二分,对于加边,若两个点连通分量不同,则连边且合并两棵Treap

启发式合并:当我们合并两棵Treap时,永远把较小的Treap中的结点加入到较大的中,这样能保证每个节点最多只被加\(O(logm)\)次(每次合并后新Treap结点个数最坏加倍),这样就保证了总复杂度为\(O(nlogm)\)

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm> 
#include <vector> 

#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())

using namespace std;

typedef long long LL;

const int maxn=300000+7;

struct Node{
 Node* ch[2];

 int v,size,rank,ind;
 int cmp(int val)
 {
  if (val==v) return -1;
  return (val<v)?(0):(1);
 }
} *root[maxn],*null;

int n,m,x,y,F[maxn],a[maxn],num[maxn],k;

char s[10];

inline int read() {
 int x=0; char c=getchar();
 while ((c<'0')||(c>'9')) c=getchar();
 while (('0'<=c)&&(c<='9')) x=x*10+(int)(c-'0'),c=getchar();
 return x;
}

//--------------------------------------------------------

inline Node* newnode() {return new Node;}

inline void maintain(Node* &o) {o->size=o->ch[0]->size+o->ch[1]->size+1;}

inline void rotate(Node* &o,int d)
{
 Node *k=o->ch[d^1]; o->ch[d^1]=k->ch[d],k->ch[d]=o;
 maintain(o),maintain(k),o=k;
}

inline void insert(Node* &o,int val,int ind)
{
 if (o==null)
  o=newnode(),o->v=val,o->size=1,o->rank=rand(),o->ch[0]=o->ch[1]=null,o->ind=ind;
 else
 {
  int d=o->cmp(val); insert(o->ch[d],val,ind),maintain(o);
  if ((o->ch[d]->rank)>(o->rank)) rotate(o,d^1);
 }
}

inline void merge(Node* &x,Node* &y) //加入结点
{
 if (x==null) return;
 insert(y,x->v,x->ind),merge(x->ch[0],y),merge(x->ch[1],y);
}

//--------------------------------------------------------

inline int find(int k) {return (F[k]==k)?(k):(F[k]=find(F[k]));}

inline void unit(int x,int y) //合并两棵Treap
{
 int fx=find(x),fy=find(y);
 if (fx==fy) return;

 if (num[fx]<num[fy])
  num[fy]+=num[fx],F[fx]=fy,merge(root[fx],root[fy]);
 else
  num[fx]+=num[fy],F[fy]=fx,merge(root[fy],root[fx]);
}

//--------------------------------------------------------

int query(Node *o,int k)
{
 int cur=o->ch[0]->size+1;

 if (k==cur) return o->ind;
 if (k<cur) return query(o->ch[0],k); else return query(o->ch[1],k-cur);
}

int main()
{
 n=read(),m=read();
 rep(i,1,n) a[i]=read(),F[i]=i,num[i]=1;
 
 null=newnode(),null->size=0;
 rep(i,1,n)
 {
  root[i]=newnode();
  root[i]->v=a[i],root[i]->size=1,root[i]->ch[0]=root[i]->ch[1]=null,root[i]->ind=i,root[i]->rank=rand();
 }

 rep(i,1,m)
 {
  x=read(),y=read();
  unit(x,y);
 }
 
 m=read();
 rep(i,1,m)
 {
  scanf("%s",s+1);
  if (s[1]=='B')
  {
   x=read(),y=read();
   unit(x,y);
  }
  else
  {
   x=read(),k=read();
   if ((x<=0)||(k<=0)) continue;
   if (k>num[find(x)]) printf("-1\n"); else printf("%d\n",query(root[find(x)],k));
  }
 }
 
 return 0;
}

posted @ 2017-02-05 23:20  Krew  阅读(102)  评论(0编辑  收藏  举报