题目描述
有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; }

本文介绍了一道基于Kruskal树算法的经典问题,通过构建Kruskal树解决特定图论问题。具体实现包括节点与边的数据结构设计、Kruskal树构建过程以及查询最大点权的高效算法。
535

被折叠的 条评论
为什么被折叠?



