題目描述
有n個節點,m條邊,點和邊都帶權
有q個如下形式的詢問:從節點x出發,經過權值不超過w的邊所能到達的所有節點中,最大的點權是多少。n,m,q≤20w
輸入
第一行:n,m
接下來一行n個數表示點權
接下來m行表示邊,每行三個數,前兩個是端點,第三個是權值
接下來一行是Q接下來Q行,每行兩個數x和w(均需要異或lastans,lastans初始爲0)
輸出
Q行
樣例輸入
6 7
2 1 4 3 5 6
1 2 2
1 4 3
2 4 3
4 5 4
2 3 4
3 5 2
5 6 5
5
2 3
1 7
6 7
4 7
6 7
樣例輸出
3
5
5
2
6
題解:Kruskal樹裸題每次從節點x出發,找到最高的點值小於等於w的點,再以其爲根找點權最大的葉子。
#include<cstdio> #include<algorithm> using namespace std; const int LOG=20; const int N=400005; int n, m, q, ans, x, w; void Getin( int &shu ) { char c; int f=1; shu=0; for( c=getchar(); c<'0'||c>'9'; c=getchar() ) if( c=='-' ) f=-1; for( ; c>='0'&&c<='9'; c=getchar() ) shu=shu*10+c-'0'; shu*=f; } int rot[N], to[N][2], fa[N][LOG+5], p[N], pcnt, maxp[N]; struct node{ int s, e, w; } cha[N>>1]; bool cmp( node a, node b ) { return a.w<b.w; } int Root( int x ) { return !rot[x] ? x: rot[x]=Root( rot[x] ); } void Kruskal() { for( int i=1; i<=m; i++ ) { int t1=Root( cha[i].s ), t2=Root( cha[i].e ); if( t1!=t2 ) { p[++pcnt]=cha[i].w; rot[t1]=rot[t2]=fa[t1][0]=fa[t2][0]=pcnt; to[pcnt][0]=t1; to[pcnt][1]=t2; maxp[pcnt]=max( maxp[t1], maxp[t2] ); } } } int Solve( int r, int w ) { for( int i=LOG; i>=0; i-- ) if( p[ fa[r][i] ] && p[ fa[r][i] ]<=w ) r=fa[r][i]; return maxp[r]; } int main() { Getin(n); Getin(m); pcnt=n; for( int i=1; i<=n; i++ ) Getin( p[i] ), maxp[i]=p[i]; for( int i=1; i<=m; i++ ) Getin( cha[i].s ), Getin( cha[i].e ), Getin( cha[i].w ); sort( cha+1, cha+m+1, cmp ); Kruskal(); for( int j=1; j<=LOG; j++ ) for( int i=1; i<=pcnt; i++ ) fa[i][j]=fa[ fa[i][j-1] ][j-1]; Getin(q); for( int i=1; i<=q; i++ ) { Getin(x); x^=ans; Getin(w); w^=ans; ans=Solve( x, w ); printf( "%d\n", ans ); } return 0; }