●BZOJ 3545 [ONTAK2010]Peaks(离线)

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=3545

http://www.lydsy.com/JudgeOnline/problem.php?id=3551(同题,强制在线,题解)

题解:

最小生成树 Kruskal,线段树(合并),离线
首先把询问和边放在一起,按权值大小从小到大排序。
然后对每个点建一棵权值线段树,维护当前联通块里的海拔权值区间内的山的个数
然后按照 Kruskal 算法合并联通块,并且合并两个联通块对应的线段树(Merge操作看代码,感觉很暴力)。
然后对于一个枚举到的询问,其起点所在的联通块里的点一定是可以到达的,
所以就用线段树查询该联通块里的第k高的山就好了。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100500
using namespace std;
struct Oper{
	int type,w,a,b;
	bool operator <(const Oper &rtm) const{
		if(w!=rtm.w) return w<rtm.w;
		return type<rtm.type;
	}
}O[MAXN*10];
struct SGT{
	int rt[MAXN],ls[MAXN*50],rs[MAXN*50],cnt[MAXN*50],sz;
	void Modify(int &u,int l,int r,int p){
		if(!u) u=++sz;
		if(l==r){cnt[u]++; return;}
		int mid=(l+r)>>1; cnt[u]++;
		if(p<=mid) Modify(ls[u],l,mid,p); 
		else Modify(rs[u],mid+1,r,p);
	}
	int Merge(int u,int v){
		if(!u||!v) return u+v;
		cnt[u]+=cnt[v];
		ls[u]=Merge(ls[u],ls[v]);
		rs[u]=Merge(rs[u],rs[v]);
		return u;
	}
	int Query(int u,int l,int r,int p){
		if(l==r) return l;
		int mid=(l+r)>>1;
		if(p<=cnt[rs[u]]) return Query(rs[u],mid+1,r,p);
		else return Query(ls[u],l,mid,p-cnt[rs[u]]);
	}
}T;
int Fa[MAXN],H[MAXN],ANS[5*MAXN];
int N,M,Q,Ont;
void read(int &x){
	static int f; static char ch;
	x=0; f=1; ch=getchar();
	while(ch<'0'||'9'<ch){if(ch=='-') f=-1; ch=getchar();}
	while('0'<=ch&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
	x=x*f;
}
int find(int x){
	return x==Fa[x]?x:Fa[x]=find(Fa[x]);
}
int main(){
	static int tmp[MAXN],tnt=0;
	read(N); read(M); read(Q);
	for(int i=1;i<=N;i++) 
		Fa[i]=i,read(H[i]),tmp[++tnt]=H[i];
	for(int i=1;i<=M;i++) 
		read(O[++Ont].a),read(O[Ont].b),read(O[Ont].w),O[Ont].type=0;
	for(int i=1;i<=Q;i++)
		read(O[++Ont].a),read(O[Ont].w),read(O[Ont].b),O[Ont].type=i;
	sort(tmp+1,tmp+tnt+1); tnt=unique(tmp+1,tmp+tnt+1)-tmp-1;
	for(int i=1;i<=N;i++) 
		H[i]=lower_bound(tmp+1,tmp+tnt+1,H[i])-tmp,
		T.Modify(T.rt[i],1,tnt,H[i]);
	sort(O+1,O+Ont+1);
	for(int i=1,f,fa,fb,p;i<=Ont;i++){
		if(O[i].type){
			f=find(O[i].a);
			if(T.cnt[T.rt[f]]<O[i].b) 
				ANS[O[i].type]=-1;
			else p=T.Query(T.rt[f],1,tnt,O[i].b),ANS[O[i].type]=tmp[p];
		}
		else{
			fa=find(O[i].a); fb=find(O[i].b);
			if(fa==fb) continue; Fa[fb]=fa;
			T.rt[fa]=T.Merge(T.rt[fa],T.rt[fb]);
		}
	}
	for(int i=1;i<=Q;i++) printf("%d\n",ANS[i]);
	return 0;
}

posted @ 2017-12-19 15:09  *ZJ  阅读(121)  评论(0编辑  收藏  举报