[BZOJ3551][ONTAK2010]Peaks加强版

bzoj

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

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

Sample Input

10 11 4
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
1 5 2
1 5 6
1 5 8
8 9 2

Sample Output

6
1
-1
8

HINT

「数据范围」\(N<=10^5,M,Q<=5*10^5,h_i,c,x<=10^9\)

sol

\(Kruskal\)重构树+树上倍增+主席树
重构树之后,从一个点开始经过权值不超过\(x\)的边能够到达的点刚好是一个子树,所以就变成了区间\(Kth\)
具体是哪一棵子树呢?考虑到重构树上非叶子节点的点权(也就是原图中的边权)是随深度单调的,所以可以写一个树上倍增求一个点最浅的权值小于等于\(x\)的祖先。
注意\(v\)是节点编号!\(x\)是权值限制!
剩下的就都是板子了。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 2e5+5;
const int M = 5e5+5;
struct edge{
	int u,v,w;
	bool operator < (const edge &b) const
		{return w<b.w;}
}E[M];
struct president_tree{int ls,rs,num;}t[N*20];
int n,m,q,num,h[N],o[N],len,to[N],nxt[N],head[N],cnt,fa[N],val[N],pa[20][N],dfn[N],low[N],ref[N],rt[N],tot,ans;
void link(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void dfs(int u,int f)
{
	pa[0][u]=f;
	for (int i=1;i<=19;++i)
		pa[i][u]=pa[i-1][pa[i-1][u]];
	if (u<=n) {dfn[u]=low[u]=++cnt;ref[cnt]=u;return;}
	for (int e=head[u];e;e=nxt[e])
		dfs(to[e],u),dfn[u]=min(dfn[u],dfn[to[e]]),low[u]=max(low[u],low[to[e]]);
}
void modify(int &x,int l,int r,int p)
{
	t[++tot]=t[x];t[x=tot].num++;
	if (l==r) return;int mid=l+r>>1;
	if (p<=mid) modify(t[x].ls,l,mid,p);
	else modify(t[x].rs,mid+1,r,p);
}
int query(int A,int B,int l,int r,int k)
{
	if (l==r) return o[l];
	int mid=l+r>>1,sum=t[t[A].rs].num-t[t[B].rs].num;
	if (k<=sum) return query(t[A].rs,t[B].rs,mid+1,r,k);
	else return query(t[A].ls,t[B].ls,l,mid,k-sum);
}
int solve(int x,int v,int k)
{
	int u=x;
	for (int i=19;~i;--i)
		if (pa[i][u]&&val[pa[i][u]]<=v) u=pa[i][u];
	if (low[u]-dfn[u]+1<k) return -1;
	return query(rt[low[u]],rt[dfn[u]-1],1,len,k);
}
int main()
{
	n=num=gi();m=gi();q=gi();
	for (int i=1;i<=n;++i) fa[i]=i,h[i]=o[++len]=gi();
	sort(o+1,o+len+1);len=unique(o+1,o+len+1)-o-1;
	for (int i=1;i<=n;++i) h[i]=lower_bound(o+1,o+len+1,h[i])-o;
	for (int i=1;i<=m;++i) E[i]=(edge){gi(),gi(),gi()};
	sort(E+1,E+m+1);
	for (int i=1;i<=m;++i)
		if (find(E[i].u)^find(E[i].v))
		{
			++num;
			val[num]=E[i].w;link(num,find(E[i].u));link(num,find(E[i].v));
			fa[find(E[i].u)]=fa[find(E[i].v)]=fa[num]=num;
		}
	memset(dfn,63,sizeof(dfn));cnt=0;
	for (int i=1;i<=num;++i) if (fa[i]==i) dfs(i,0);
	for (int i=1;i<=n;++i) modify(rt[i]=rt[i-1],1,len,h[ref[i]]);
	while (q--)
	{
		int x=gi(),v=gi(),k=gi();
		if (ans!=-1) v^=ans,x^=ans,k^=ans;
		printf("%d\n",ans=solve(x,v,k));
	}
	return 0;
}
posted @ 2018-03-23 15:30  租酥雨  阅读(398)  评论(0编辑  收藏  举报