您的位置:首页 > 其它

BZOJ 2733: [HNOI2012]永无乡 (Treap+启发式合并)

2017-01-06 14:54 567 查看

BZOJ 2733: [HNOI2012]永无乡

题目概述:

n座岛屿,给出m座桥连接不同的两座岛屿.

现在有两种操作:

1.在两座不同岛屿间架设一座桥梁.

2.询问某一岛屿与之相连的岛屿(包括该岛屿)中重要度第k小的岛屿编号,若不存在,为-1.

输出所有第二种操作的答案.

题目分析:

先建n棵Treap实现第二种操作.

对于两棵Treap的合并,采用启发式合并,选择将节点数少的一个一个插入到节点数多的.既然要将一棵树的所有结点插到另一棵树里,可以选择dfs遍历一遍.

再用并查集维护每个结点所在集合.

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

const int maxn=100000+10;

char readchar() {
char ch=getchar();
while(ch<'A'||ch>'Z') ch=getchar();
return ch;
}

struct Node {
Node* ch[2];
int key,rnd,sz,id;
Node(){}
Node(int key,int id):key(key),id(id){rnd=rand();sz=1;ch[0]=ch[1]=NULL;}
void update() {
sz=1;
if(ch[0]) sz+=ch[0]->sz;
if(ch[1]) sz+=ch[1]->sz;
}
}*root[maxn],*pool[maxn];

int top;

void init() {top=0;for(int i=0;i<maxn;i++) pool[i]=new Node();}
Node* new_node() {return pool[top++];}
void del_node(Node* &u) {pool[--top]=u;u=NULL;}

void rotate(Node* &u,int d) {
Node* v=u->ch[d^1];u->ch[d^1]=v->ch[d];v->ch[d]=u;
u->update();(u=v)->update();
}

void insert(Node* &u,Node v) {
if(!u) {
u=new_node();(*u)=v;
return ;
}
int d=v.key>u->key;
insert(u->ch[d],v);++(u->sz);
if(u->rnd>u->ch[d]->rnd) rotate(u,d^1);
}

#define lc (u->ch[0])
#define rc (u->ch[1])

int find_id(Node* u,int rnk) {
while(u) {
int d=lc?lc->sz:0;
if(rnk<=d) u=lc;
else if(rnk>d+1) rnk-=d+1,u=rc;
else return u->id;
}
return -1;
}

int fa[maxn];

int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}

void dfs(Node* &A,Node* &B) {//dfs遍历一遍B树,将其所有结点插入A树
if(!B) return ;
if(B->ch[0]) dfs(A,B->ch[0]);
if(B->ch[1]) dfs(A,B->ch[1]);
insert(A,*B);del_node(B);
}

void merge(int x,int y) {//启发式合并
int fx=find(x),fy=find(y);
if(fx==fy) return ;
if(root[fx]->sz<root[fy]->sz) swap(x,y),swap(fx,fy);
dfs(root[fx],root[fy]);fa[fy]=fx;
}

int main() {
init();
int n,m,k,u,v,q;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%d",&k);fa[i]=i;
insert(root[i],Node(k,i));
}
while(m--) {
scanf("%d%d",&u,&v);
merge(u,v);
}
scanf("%d",&q);
while(q--) {
if(readchar()=='B') {
scanf("%d%d",&u,&v);
merge(u,v);
} else {
scanf("%d%d",&u,&v);
printf("%d\n",find_id(root[find(u)],v));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: