BZOJ3551 [ONTAK2010]Peaks加强版 kruskal 并查集 主席树 dfs序

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ3551


题意概括

Description

在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。

Input

第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。

Output

对于每组询问,输出一个整数表示答案。


题解

  毒瘤题

  作为蒟蒻的我不敢写题解了。

  给个好链接:http://blog.csdn.net/PoPoQQQ/article/details/41348785


代码

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=100005,M=500005,S=N*2,Inf=1e9+5;
struct Edge{
	int x,y,z;
	void read(){
		scanf("%d%d%d",&x,&y,&z);
	}
}e[M];
bool cmpz(Edge a,Edge b){
	return a.z<b.z;
}
struct MQset{//并查集 
	int cnt,fa[N*2];
	void clear(){cnt=0;}
	int getf(int k){return fa[k]==k?k:fa[k]=getf(fa[k]);}
	void push(int x){fa[x]=x;}
	void merge(int x,int y){fa[getf(x)]=getf(y);}
}s;
int n,m,q,h[N];
int fa[S],lc[S],rc[S],val[S],cnt;
int anst[S][20],time,in[S],out[S],dfn[S];
void dfs(int rt){
	anst[rt][0]=fa[rt];
	for (int i=1;i<20;i++)
		anst[rt][i]=anst[anst[rt][i-1]][i-1];
	in[rt]=time;
	if (!lc[rt])
		dfn[++time]=rt;
	else
		dfs(lc[rt]),dfs(rc[rt]);
	out[rt]=time;
}
const int SIZE=N*2*20*2;
int Ha[N],hs;
int ls[SIZE],rs[SIZE],sum[SIZE],total,root[N];
void LSH(){
	int hs_=1;
	sort(Ha+1,Ha+hs+1);
	for (int i=2;i<=hs;i++)
		if (Ha[i]!=Ha[i-1])
			Ha[++hs_]=Ha[i];
	hs=hs_;
}
int find(int x){
	return lower_bound(Ha+1,Ha+hs+1,x)-Ha;
}
void build(int &rt,int L,int R){
	rt=++total;
	sum[rt]=0;
	if (L==R)
		return;
	int mid=(L+R)>>1;
	build(ls[rt],L,mid);
	build(rs[rt],mid+1,R);
}
void add(int prt,int &rt,int L,int R,int pos){
	rt=++total;
	if (L==R){
		sum[rt]=sum[prt]+1;
		return;
	}
	int mid=(L+R)>>1;
	if (pos<=mid)
		add(ls[prt],ls[rt],L,mid,pos),rs[rt]=rs[prt];
	else
		add(rs[prt],rs[rt],mid+1,R,pos),ls[rt]=ls[prt];
	sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
int query(int prt,int rt,int L,int R,int k){
	if (L==R)
		return Ha[L];
	int Rz=sum[rs[rt]]-sum[rs[prt]];
	int mid=(L+R)>>1;
	if (Rz>=k)
		return query(rs[prt],rs[rt],mid+1,R,k);
	else
		return query(ls[prt],ls[rt],L,mid,k-Rz);
}
int find(int x,int v){
	for (int i=19;i>=0;i--)
		if (val[anst[x][i]]<=v)
			x=anst[x][i];
	return x;
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for (int i=1;i<=n;i++)
		scanf("%d",&h[i]),Ha[i]=h[i];
	hs=n;
	LSH();
	for (int i=1;i<=n;i++)
		h[i]=find(h[i]);
	for (int i=1;i<=m;i++)
		e[i].read();
	sort(e+1,e+m+1,cmpz);
	s.clear();
	for (int i=1;i<=n;i++){
		s.push(i);
		fa[i]=lc[i]=rc[i]=val[i]=0;
	}
	cnt=n;
	for (int i=1;i<=m;i++){
		int x=e[i].x,y=e[i].y,z=e[i].z;
		x=s.getf(x),y=s.getf(y);
		if (x==y)
			continue;
		s.push(++cnt);
		fa[x]=fa[y]=cnt;
		fa[cnt]=0,lc[cnt]=x,rc[cnt]=y,val[cnt]=z;
		s.fa[x]=s.fa[y]=cnt;
	}
	val[0]=Inf;
	time=0;
	dfs(cnt);
	build(root[0],1,n);
	for (int i=1;i<=n;i++)
		add(root[i-1],root[i],1,n,h[dfn[i]]);
	int lastans=0;
	for (int i=1;i<=q;i++){
		int v,x,k,y;
		scanf("%d%d%d",&v,&x,&k);
		if (~lastans)
			v^=lastans,x^=lastans,k^=lastans;
		y=find(v,x);
		if (out[y]-in[y]<k)
			lastans=-1;
		else
			lastans=query(root[in[y]],root[out[y]],1,n,k);
		printf("%d\n",lastans);
	}
	return 0;
}

  

posted @ 2017-12-18 16:05  zzd233  阅读(308)  评论(0编辑  收藏  举报