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]]