BZOJ 2733 HNOI2012 永无乡 Treap+启发式合并

题目大意:给定一个无向图以及n个点的排名,多次连接一条边,多次求某个点所在联通块中排名第k小的点的编号

初始对于每个点建立一棵只有一个节点的Treap,然后每次连接两个点,利用并查集找到两个点的根节点,将size较小的Treap暴力拆解插入大的中,然后将小的并查集合并到大的中

今天下午各种脑残,一个小小的Treap改了不下10遍0.0 快去喝脑白金0.0

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
struct abcd{
	abcd *ls,*rs;
	int num,key;
	int siz;
	abcd(int x);
	void Maintain();
}*null=new abcd(0),*tree[M];
int n,m,q,a[M];
int fa[M],siz[M];
abcd :: abcd(int x)
{
	ls=rs=null;
	num=x;
	if(!x)
		key=0,siz=0;
	else
		key=rand(),siz=1;
}
void abcd :: Maintain()
{
	siz=ls->siz+rs->siz+1;
}
void Zig(abcd *&x)
{
	abcd *y=x->ls;
	x->ls=y->rs;
	y->rs=x;
	x=y;
	x->rs->Maintain();
	x->Maintain();
}
void Zag(abcd *&x)
{
	abcd *y=x->rs;
	x->rs=y->ls;
	y->ls=x;
	x=y;
	x->ls->Maintain();
}
void Insert(abcd *&x,abcd *y)
{
	if(x==null)
	{
		x=y;
		x->ls=x->rs=null;
		x->Maintain();
		return ;
	}
	if(y->num<x->num)
	{
		Insert(x->ls,y);
		if(x->ls->key>x->key)
			Zig(x);
	}
	else
	{
		Insert(x->rs,y);
		if(x->rs->key>x->key)
			Zag(x);
	}
	x->Maintain();
}
void Decomposition(abcd *x,int y)
{
	if(x==null)
		return ;
	Decomposition(x->ls,y);
	Decomposition(x->rs,y);
	Insert(tree[y],x);
}
int Rank(abcd *x,int k)
{
	if(x==null)
		return 0;
	int temp=x->ls->siz;
	if(k<=temp)
		return Rank(x->ls,k);
	k-=temp;
	if(k==1)
		return x->num;
	--k;
	return Rank(x->rs,k);
}
int Find(int x)
{
	if(!fa[x])
		fa[x]=x,siz[x]=1;
	if(fa[x]==x)
		return fa[x]=x;
	return fa[x]=Find(fa[x]);
}
void Merge(int x,int y)
{
	int fx=Find(x),fy=Find(y);
	if(fx==fy)
		return ;
	if(siz[fx]>siz[fy])
		swap(x,y),swap(fx,fy);
	Decomposition(tree[fx],fy);
	fa[fx]=fy;
	siz[fy]+=siz[fx];
}
int main()
{
	int i,x,y;
	char p[10];
	cin>>n>>m;
	a[0]=-1;
	for(i=1;i<=n;i++)
		scanf("%d",&x),tree[i]=new abcd(x),a[x]=i;
	for(i=1;i<=m;i++)
		scanf("%d%d",&x,&y),Merge(x,y);
	cin>>q;
	for(i=1;i<=q;i++)
	{
		scanf("%s%d%d",p,&x,&y);
		if(p[0]=='Q')
			printf("%d\n",a[Rank(tree[Find(x)],y)]);
		else
			Merge(x,y);
	}
}
时间: 2024-10-15 07:06:31

BZOJ 2733 HNOI2012 永无乡 Treap+启发式合并的相关文章

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

不难...treap + 启发式合并 + 并查集 搞搞就行了 ---------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep(i, n) for(int i = 0; i &l

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

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2733 [题目大意] 给出n个点,每个点都有自己的重要度,现在有连边操作和查询操作, 查询操作要求找出一个连通块中重要度第k的点的id [题解] 我们用Treap维护每个连通块,对于连边操作,我们用启发式合并, 将size比较小的Treap并入size比较大的Treap,同时用并查集维护连通信息 [代码] #include <cstdio> #include <algorith

Bzoj 2733: [HNOI2012]永无乡 数组Splay+启发式合并

2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3955  Solved: 2112[Submit][Status][Discuss] Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达

bzoj 2733: [HNOI2012]永无乡 离线+主席树

2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1167  Solved: 607[Submit][Status] Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a

[BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)

Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k

bzoj 2733: [HNOI2012]永无乡

23333用并查集维护联通,然后网上搞splay就行啦. %高端splay写法(2333写在struct里了,是不是叫构造函数什么的??) 1 #include<bits/stdc++.h> 2 #define N 100005 3 #define LL long long 4 #define ls tr[x][0] 5 #define rs tr[x][1] 6 using namespace std; 7 inline int ra() 8 { 9 int x=0,f=1; char ch

【bzoj2733】[HNOI2012]永无乡 线段树合并

Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛.如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的.现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥.Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k

【BZOJ2733】永无乡[splay启发式合并or线段树合并]

题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被这坑了. 网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 这道题似乎挺经典的(至少我看许多神犇很早就做了这道题).这道题有两种写法:并查集+(splay启发式合并or线段树合并).我写的是线段树合并,因为--splay不会打+懒得学.

BZOJ 2733 HNOI 2012 永无乡 平衡树启发式合并

题目大意:有一些岛屿,一开始由一些无向边连接.后来也有不断的无向边加入,每一个岛屿有个一独一无二的重要度,问任意时刻的与一个岛屿联通的所有岛中重要度第k大的岛的编号是什么. 思路:首先连通性一定要用并查集维护,然后就是联通快内的第k大问题,显然是平衡树.但是并查集的合并怎么搞?可以考虑按秩合并,这样的话就保证每次在平衡树中处理的元素尽量的少,就可以水过这个题了. 注意一下输出-1的判断. CODE: #include <map> #include <cstdio> #include