【并查集套可持久化线段树】【bzoj 2733】: [HNOI2012]永无乡


2733: [HNOI2012]永无乡

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1178   Solved: 614
[ Submit][ Status]

Description

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

Input

输入文件第一行是用空格隔开的两个正整数 n 和 m,分别 表示岛的个数以及一开始存在的桥数。接下来的一行是用空格隔开的 n 个数,依次描述从岛 1 到岛 n 的重要度排名。随后的 m 行每行是用空格隔开的两个正整数 ai 和 bi,表示一开始就存 在一座连接岛 ai 和岛 bi 的桥。后面剩下的部分描述操作,该部分的第一行是一个正整数 q, 表示一共有 q 个操作,接下来的 q 行依次描述每个操作,操作的格式如上所述,以大写字母 Q 或B 开始,后面跟两个不超过 n 的正整数,字母与数字以及两个数字之间用空格隔开。 对于 20%的数据 n≤1000,q≤1000 
 
对于 100%的数据 n≤100000,m≤n,q≤300000 
 

Output

对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表 示所询问岛屿的编号。如果该岛屿不存在,则输出-1。 
 

Sample Input

5 1
4 3 2 5 1
1 2
7
Q 3 2
Q 2 1
B 2 3
B 1 5
Q 2 1
Q 2 4
Q 2 3

Sample Output

-1
2
5
1
2

题意:
n个独立点有各不相同的权值
开始合并m次,每次合并两个点所在集合
两种操作
Q x y 询问x所在集合的权值第y大的点
B x y 合并x、y的所在集合


输入:
n,m
n个点,m条初始边
n个数,每个点的权值
m行
每行a、b
合并a、b所在集合
接下来一个q
q行
Q x y 询问x所在集合的权值第y大的点
B x y 合并x、y的所在集合


线段树+并查集
代码画个图,也挺容易理解的 
 
这是自己YY hzwer 神犇的代码,考试的时候花半个多小时默写了一遍 
但是不知复杂度如何计算,总觉得merge的复杂度大于O(logn) 
还有不知道数组应该开多大,我觉得要开nlogn ,算出来比实际值小了一点


考完发现过了样例就交,竟然1A了。结果考试完挂。。。


代码比hzwer慢了一点,不知为什么


#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
/************************************************
Code By willinglive

线段树+并查集
代码画个图,也挺容易理解的 
 
这是自己YY hzwer 神犇的代码,考试的时候花半个多小时默写了一遍 
但是不知复杂度如何计算,总觉得merge的复杂度大于O(logn) 
还有不知道数组应该开多大,我觉得要开nlogn 

Oct.30,2014
************************************************/
/
#define rep(i,l,r) for(int i=l,___t=(r);i<=___t;i++)
#define per(i,r,l) for(int i=r,___t=(l);i>=___t;i--)
#define LL long long
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define INE(i,u,e) for(int i=head[u];~i;i=e[i].next)
/
const int N=100010;
int n,m,q;

int fa[N];
int rank[N];

int root[N],ls[1800000],rs[1800000];
int sum[1800000],sz;
int val[1800000];

int id[N];//权值 -> 点 
/
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
inline int getint()
{
	int res=0;char c=getchar();
	while(!isdigit(c))c=getchar();
	while(isdigit(c))res=res*10+c-'0',c=getchar();
	return res;
}

void insert(int &o,int pos,int l,int r)
{
	if(!o) o=++sz;
	if(l==r) {val[o]=pos;sum[o]=1;return;}
	int mid=(l+r)>>1;
	if(pos<=mid) insert(ls[o],pos,l,mid);
	else	     insert(rs[o],pos,mid+1,r);
	sum[o]=sum[ls[o]]+sum[rs[o]];
}
int query(int o,int pos)
{
	if(sum[o]==1)
	{
		if(ls[o]) return query(ls[o],pos);
		else if(rs[o]) return query(rs[o],pos);
		return val[o];
	}
	if(sum[ls[o]]>=pos) return query(ls[o],pos);
	else return query(rs[o],pos-sum[ls[o]]);
}
void merge(int &x,int &y)
{
	if(x==0){x=y;return;}
	if(y==0){y=x;return;}
	merge(ls[x],ls[y]);
	merge(rs[x],rs[y]);
	sum[x]=sum[ls[x]]+sum[rs[x]];
	sum[y]=sum[ls[y]]+sum[rs[y]];
}
/
void input()
{
    n=getint(); m=getint();
    rep(i,1,n) rank[i]=getint(),fa[i]=i,id[rank[i]]=i;
    rep(i,1,m) fa[find(getint())]=find(getint());
    q=getint();
}
void solve()
{
    /
    char op[5];
    int x,y;
    /
    rep(i,1,n) insert(root[find(i)],rank[i],1,n);
    
    while(q--)
    {
    	scanf("%s",op);
    	x=getint(); y=getint();
    	if(op[0]=='Q')
    	{
    		int fx=find(x);
    		if(sum[root[fx]]



你可能感兴趣的:(高级数据结构)