[ONTAK2010] Peaks加强版 (kruskal重构树+主席树+倍增)
Peaks
- description
- solution
- code
description
在Bytemountains有N座山峰,每座山峰有他的高度h_i
有些山峰之間有雙向道路相連,共M條路徑,每條路徑有一個(gè)困難值,這個(gè)值越大表示越難走
現(xiàn)在有Q組詢問,每組詢問詢問從點(diǎn)v開始只經(jīng)過困難值小于等于x的路徑所能到達(dá)的山峰中第k高的山峰,如果無(wú)解輸出-1。
Input
第一行三個(gè)數(shù)N,M,Q
第二行N個(gè)數(shù),第i個(gè)數(shù)為h_i
接下來M行,每行3個(gè)數(shù)a b c,表示從a到b有一條困難值為c的雙向路徑
接下來Q行,每行三個(gè)數(shù)v x k,表示一組詢問
Output
對(duì)于每組詢問,輸出一個(gè)整數(shù)表示答案。
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 2Sample Output
6 1 -1 8Hint
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,又是這種限制題,很容易聯(lián)想到前幾天才寫的[NOI2018]歸程
套路的,要對(duì)邊權(quán)進(jìn)行排序,(通常還會(huì)有一步離散化),然后建立主席樹,每個(gè)iii版本的線段樹表示邊權(quán)≤xi\le x_i≤xi?的所有邊存在的樹/圖
本題思想是一致的,但是實(shí)現(xiàn)不同
使用kruskal重構(gòu)樹
重構(gòu)后,對(duì)樹dfn編序
葉子節(jié)點(diǎn)就表示該節(jié)點(diǎn)的高度,非葉子節(jié)點(diǎn)則表示該點(diǎn)子樹內(nèi)最大邊權(quán)
每次查詢的最大邊限制x,就可以從v開始倍增地在dfs樹上跳邊,直到跳到某個(gè)祖先節(jié)點(diǎn)存的值是最大的小于等于x的邊權(quán),此時(shí)再往上跳邊權(quán)就超過了x的限制
所以v能到達(dá)的點(diǎn)就是這個(gè)祖先節(jié)點(diǎn)管轄的區(qū)間內(nèi)的所有點(diǎn)
kruskal重構(gòu)樹,深度越小的點(diǎn)代表的邊權(quán)越大;實(shí)現(xiàn)是從小往上逐漸構(gòu)造出一棵MST
利用dfn序列的性質(zhì),一個(gè)點(diǎn)子樹內(nèi)dfn序是一段連續(xù)區(qū)間,可以用線段樹維護(hù)
直接線段樹里面查即可
具體而言:對(duì)每個(gè)點(diǎn)都建立權(quán)值線段樹,對(duì)每個(gè)點(diǎn)的線段樹版本可持久化,查祖先管轄區(qū)間內(nèi)的值就是其管轄區(qū)間右端點(diǎn)版本減去其管轄區(qū)間左端點(diǎn)的前一個(gè)版本
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; }總結(jié)
以上是生活随笔為你收集整理的[ONTAK2010] Peaks加强版 (kruskal重构树+主席树+倍增)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [2020-09-11 CQBZ/HSZ
- 下一篇: BZOJ4504. K个串(主席树+优先