[BZOJ3551][ONTAK2010]Peaks加强版
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;
}