[题解]BZOJ3545&3551 Peaks

题目描述

\(n\)个点\(m\)条边的无向图,每个点和每条边都有一个权值,询问\(u,x,k\):问从\(u\)开始走边权不超过\(x\)的边所能到达的点中第\(k\)大的权值

分析

毕竟是在克鲁斯卡尔重构树的博客里面找到这题的,那么必然是要用到克鲁斯卡尔重构树的喽

发现问题可以转化成求重构树上某一个点子树内的第\(k\)大,由于子树内的节点dfs序是连续的,可以用主席树来维护。

代码

细节还挺多的

注意数组,还有主席树新建节点的时候记得复制信息

#include<bits/stdc++.h>
#define rep(X,A,B) for(int X=A;X<=B;X++)
#define tep(X,A,B) for(int X=A;X>=B;X--)
#define LL long long
const int N=400010;
const int M=500010;
const int NN=400010;
const int NNN=5000010;
const int MX=30;
using namespace std;

struct nn{
    int u,v,w;
}E[M];

int cmp(nn A,nn B){
    return A.w<B.w;
}

int n,m,T;
int a[N],hlp[N],len;
int tmp=0,dfn[NN],pt[NN],lef[NN],rit[NN],val[NN];
int tot=0,son[NNN][2],fa[NN][MX],pa[NN],dep[NN];
int sum[NNN],rt[N];

void READ(){
    int u,v,w;
    scanf("%d%d%d",&n,&m,&T);
    rep(i,1,n)scanf("%d",&a[i]),hlp[i]=a[i];
    //---
    sort(hlp+1,hlp+n+1);
    len=unique(hlp+1,hlp+n+1)-hlp-1;
    rep(i,1,n)a[i]=lower_bound(hlp+1,hlp+len+1,a[i])-hlp;
    //---
    rep(i,1,m){
        scanf("%d%d%d",&u,&v,&w);
        E[i]=(nn){u,v,w};
    }
}//chked

struct SegmentTree{
    void BUILD(int x,int l,int r){
        sum[x]=0;
        if(l==r)return;
        int mid=(l+r)>>1;
        son[x][0]=++tot;BUILD(son[x][0],l,mid);
        son[x][1]=++tot;BUILD(son[x][1],mid+1,r);
    }//chked

    void INS(int x,int las,int l,int r,int pos){
        if(l==r){
            sum[x]=sum[las]+1;//一开始写成sum[x]++挂了好久
            return;
        }
        int mid=(l+r)>>1;
        if(pos<=mid){
            son[x][0]=++tot;son[x][1]=son[las][1];
            INS(son[x][0],son[las][0],l,mid,pos);
        }
        else{
            son[x][1]=++tot;son[x][0]=son[las][0];
            INS(son[x][1],son[las][1],mid+1,r,pos);
        }
        sum[x]=sum[son[x][0]]+sum[son[x][1]];
    }

    int QUE(int x,int las,int l,int r,int pos){
        if(pos<=0)return -1;
        if(l==r)return hlp[l];
        if(sum[x]-sum[las]<pos)return -1;
        int mid=(l+r)>>1;
        int lf=sum[son[x][0]]-sum[son[las][0]];
        if(lf>=pos)return QUE(son[x][0],son[las][0],l,mid,pos);
        return QUE(son[x][1],son[las][1],mid+1,r,pos-lf);
    }
}sg;

int GETFA(int x){
    if(x!=pa[x])pa[x]=GETFA(pa[x]);
    return pa[x];
}

void SEARCH(int x){
    if(!x)return;
    if(x<=n){
        pt[++tmp]=x,dfn[x]=tmp,lef[x]=rit[x]=tmp;
        return;
    }
    SEARCH(son[x][0]);
    SEARCH(son[x][1]);
    lef[x]=lef[son[x][0]];
    rit[x]=rit[son[x][1]];
}//chked

void CHKFA(){
    SEARCH(tot);
    dep[tot]=0;
    tep(x,tot,1)dep[x]=dep[fa[x][0]]+1;
    rep(i,1,20){
        rep(x,1,tot){
            if((1<<i)>=dep[x])continue;
            fa[x][i]=fa[fa[x][i-1]][i-1];
        }
    }
}

void INIT(){
    sort(E+1,E+m+1,cmp);
    rep(i,1,n)pa[i]=i;
    tot=n;
    //---
    rep(i,1,m){
        int fu=GETFA(E[i].u),fv=GETFA(E[i].v);
        if(fu==fv)continue;
        tot++;
        val[tot]=E[i].w;
        fa[fu][0]=fa[fv][0]=tot;
        son[tot][0]=fu;son[tot][1]=fv;
        pa[fu]=pa[fv]=pa[tot]=tot;
    }
    //---
    CHKFA();
    rep(i,0,tot)son[i][0]=son[i][1]=0;
    tot=0;

    rt[0]=1;sg.BUILD(1,1,len);
    rep(i,1,n)rt[i]=++tot,sg.INS(rt[i],rt[i-1],1,len,a[pt[i]]);
    
}
int GET(int x,int mx){
    tep(i,20,0){
        if((1<<i)>=dep[x])continue;
        if(val[fa[x][i]]<=mx)x=fa[x][i];
    }
    return x;
}

void SOLVE(){
    int u,x,K;
    scanf("%d%d%d",&u,&x,&K);
    int now=GET(u,x);
    int L=lef[now],R=rit[now];
    printf("%d\n",sg.QUE(rt[R],rt[L-1],1,len,sum[rt[R]]-sum[rt[L-1]]-K+1));
}

int main(){
    READ();
    INIT();
    while(T--)SOLVE();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/SCL123/p/11761716.html
今日推荐