[BZOJ3388]peaks弱化版

13 篇文章 0 订阅
7 篇文章 1 订阅
题目描述
有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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值