Peaks
- description
- solution
- code
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<=105,M,Q<=5∗105,hi,c,x<=109N<=10^5, M,Q<=5*10^5,h_i,c,x<=10^9N<=105,M,Q<=5∗105,hi,c,x<=109
solution
困难值小于等于x,又是这种限制题,很容易联想到前几天才写的[NOI2018]归程
套路的,要对边权进行排序,(通常还会有一步离散化),然后建立主席树,每个iii版本的线段树表示边权≤xi\le x_i≤xi的所有边存在的树/图
本题思想是一致的,但是实现不同
使用kruskal
重构树
重构后,对树dfn
编序
叶子节点就表示该节点的高度,非叶子节点则表示该点子树内最大边权
每次查询的最大边限制x
,就可以从v
开始倍增地在dfs
树上跳边,直到跳到某个祖先节点存的值是最大的小于等于x
的边权,此时再往上跳边权就超过了x
的限制
所以v
能到达的点就是这个祖先节点管辖的区间内的所有点
kruskal重构树,深度越小的点代表的边权越大;实现是从小往上逐渐构造出一棵MST
利用dfn
序列的性质,一个点子树内dfn
序是一段连续区间,可以用线段树维护
直接线段树里面查即可
具体而言:对每个点都建立权值线段树,对每个点的线段树版本可持久化,查祖先管辖区间内的值就是其管辖区间右端点版本减去其管辖区间左端点的前一个版本
code
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 500005
int n, m, Q, cnt;
vector < int > G[maxn];
struct edge { int u, v, w; } E[maxn];
struct node { int lson, rson, tot; } t[maxn * 30];
int St[maxn], Ed[maxn], fa[maxn], h[maxn], d[maxn], root[maxn], id[maxn], dfn[maxn];
int f[maxn][20];int find( int x ) { return x == fa[x] ? x : fa[x] = find( fa[x] ); }void dfs( int u, int p ) {dfn[St[u] = ++ cnt] = u, f[u][0] = p;for( int i = 1;i < 20;i ++ )f[u][i] = f[f[u][i - 1]][i - 1];for( auto v : G[u] ) dfs( v, u );Ed[u] = cnt;
}void modify( int &now, int lst, int l, int r, int pos ) {t[now = ++ cnt] = t[lst];t[now].tot ++; if( l == r ) return;int mid = ( l + r ) >> 1;if( pos <= mid ) modify( t[now].lson, t[lst].lson, l, mid, pos );else modify( t[now].rson, t[lst].rson, mid + 1, r, pos );
}int query( int L, int R, int l, int r, int k ) {if( l == r ) return l;int x = t[t[R].lson].tot - t[t[L].lson].tot;int mid = ( l + r ) >> 1;if( k <= x ) return query( t[L].lson, t[R].lson, l, mid, k );else return query( t[L].rson, t[R].rson, mid + 1, r, k - x );
}int main() {scanf( "%d %d %d", &n, &m, &Q );for( int i = 1;i <= n;i ++ )scanf( "%d", &h[i] ), d[i] = h[i];sort( d + 1, d + n + 1 );int tot = unique( d + 1, d + n + 1 ) - d - 1;for( int i = 1;i <= n;i ++ )h[i] = lower_bound( d + 1, d + tot + 1, h[i] ) - d;for( int i = 1;i <= m;i ++ )scanf( "%d %d %d", &E[i].u, &E[i].v, &E[i].w );sort( E + 1, E + m + 1, []( edge x, edge y ) { return x.w < y.w; } );for( int i = 1;i <= n;i ++ ) id[i] = fa[i] = i;int N = n;for( int i = 1;i <= m;i ++ ) {int u = find( E[i].u ), v = find( E[i].v ), w = E[i].w;if( u ^ v ) {h[++ N] = w;G[N].push_back( id[u] );G[N].push_back( id[v] );id[fa[v] = u] = N;}}dfs( N, N );for( int i = 1;i <= N;i ++ )if( dfn[i] <= n ) modify( root[i], root[i - 1], 1, tot, h[dfn[i]] );else root[i] = root[i - 1];int lastans = -1, v, x, k;while( Q -- ) {scanf( "%d %d %d", &v, &x, &k );if( ~ lastans ) v ^= lastans, x ^= lastans, k ^= lastans;for( int i = 19;~ i;i -- )if( h[f[v][i]] <= x ) v = f[v][i];x = t[root[Ed[v]]].tot - t[root[St[v] - 1]].tot;if( x < k )x = -1;elsex = query( root[St[v] - 1], root[Ed[v]], 1, tot, x - k + 1 );printf( "%d\n", lastans = ( ~ x ) ? d[x] : -1 );}return 0;
}