[BZOJ3388]peaks弱化版

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章