【BZOJ 3551】Peaks加強版

題目描述

在 Bytemountains 有 NN 座山峯,每座山峯有他的高度 hih_i。有些山峯之間有雙向道路相連,共 MM 條路徑,每條路徑有一個困難值,這個值越大表示越難走,現在有 QQ 組詢問,每組詢問詢問從點 vv 開始只經過困難值小於等於 xx 的路徑所能到達的山峯中第 kk 高的山峯,如果無解輸出 1-1N105N\le 10^5M,Q5×105M,Q\le 5\times 10^5hi,c,x109h_i,c,x\le 10^9

算法分析

學習了一下 Kruskal 重構樹,本題利用了 Kruskal 重構樹的堆性質,只需要樹上倍增找到能走到的最接近根節點的祖先,所有能到達的山峯就是其所在子樹的所有葉子節點,可以用 DFS 序+主席樹維護子樹中的葉子節點權值。

細節有主席樹求區間第 kk 小而本題要求區間第 kk 大,需要簡單轉化一下,還有注意維護的是子樹中葉子節點的權值。還有個細節:原來的節點數不一定等於 n2+1\lfloor\frac{n}{2}\rfloor+1,因爲圖不一定連通吧。

【BZOJ 3545】Peaks 爲不強制在線的版本,雙倍經驗哦。

代碼實現

#include <cstdio>
#include <algorithm>
const int maxn=(int)1e5+5;
const int maxm=(int)5e5+5;
char buf[1<<15],*fs=buf,*ft=buf;
inline char gc() {
    if(fs==ft) {
        ft=(fs=buf)+fread(buf,1,1<<15,stdin);
        if(fs==ft) return 0;
    }
    return *fs++;
}
inline void read(int &num) {
    char c=gc();int f=false;num=0;
    while(c<'0'||'9'<c) {if(c=='-') f=true;c=gc();}
    while('0'<=c&&c<='9') {num=num*10+c-'0';c=gc();}
    if(f) num=-num;
}
int sum[maxn<<6],lch[maxn<<6],rch[maxn<<6],cnt=0;
int ins(int o,int l,int r,int x) {
    int mid=(l+r)>>1,nxt=++cnt;
    if(l==r) sum[nxt]=sum[o]+1;
    else {
        lch[nxt]=(x<=mid)?ins(lch[o],l,mid,x):lch[o];
        rch[nxt]=(mid+1<=x)?ins(rch[o],mid+1,r,x):rch[o];
        sum[nxt]=sum[lch[nxt]]+sum[rch[nxt]];
    }
    return nxt;
}
int query(int x,int y,int l,int r,int k) {
    int mid=(l+r)>>1;if(l==r) return mid;
    int lcnt=sum[lch[y]]-sum[lch[x]];
    if(k<=lcnt) return query(lch[x],lch[y],l,mid,k);
    return query(rch[x],rch[y],mid+1,r,k-lcnt);
}
struct edge {int u,v,w;} e[maxm];
inline bool cmp(const edge &x,const edge &y) {return x.w<y.w;}
int head[maxn<<1],ev[maxn<<1],nxt[maxn<<1],idx=0;
inline void add(int u,int v) {ev[++idx]=v;nxt[idx]=head[u];head[u]=idx;}
int fa[maxn<<1];int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
int ha[maxn],sz=0;inline int ask(int x) {return std::lower_bound(ha,ha+sz,x)-ha+1;}
int h[maxn<<1],pa[maxn<<1][20],rt[maxn<<1],tot[maxn<<1],dl[maxn<<1],dfn[maxn<<1],dfsidx=0;
void dfs(int x,int fa) {
    dl[dfn[x]=++dfsidx]=x;tot[x]=1;
    for(register int i=head[x];i;i=nxt[i]) {
        int v=ev[i];dfs(v,x);tot[x]+=tot[v];
    }
}
int main() {
    int ln,n,m,q;read(n);ln=n;read(m);read(q);
    for(register int i=1;i<=n;++i) {read(h[i]);ha[i-1]=h[i];}
    std::sort(ha,ha+n);sz=std::unique(ha,ha+n)-ha;
    for(register int i=0;i<m;++i) {read(e[i].u);read(e[i].v);read(e[i].w);}
    std::sort(e,e+m,cmp);
    for(register int i=1;i<=(n<<1);++i) fa[i]=i;
    for(register int i=0;i<m;++i) {
        int x=find(e[i].u),y=find(e[i].v);if(x==y) continue;
        ++n;h[n]=e[i].w;pa[x][0]=pa[y][0]=fa[x]=fa[y]=n;add(n,x);add(n,y);
    }
    for(register int i=1;i<20;++i) for(register int x=1;x<=n;++x) pa[x][i]=pa[pa[x][i-1]][i-1];
    dfs(n,0);for(register int i=1;i<=n;++i) rt[i]=(dl[i]<=ln)?ins(rt[i-1],1,sz,ask(h[dl[i]])):rt[i-1];
    int v,x,k,la=0;
    while(q--) {
        read(v);read(x);read(k);if(~la) {v^=la;x^=la;k^=la;}
        for(int i=19;i>=0;--i) if(pa[v][i]&&h[pa[v][i]]<=x) v=pa[v][i];
        int l=dfn[v],r=dfn[v]+tot[v]-1,cnt=sum[rt[r]]-sum[rt[l-1]];
        printf("%d\n",la=(k<=cnt?ha[query(rt[l-1],rt[r],1,sz,cnt+1-k)-1]:-1));
    }
    return 0;
}

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