1. 程式人生 > >【BZOJ 3551】Peaks加強版

【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 大,需要簡單轉化一下,還有注意維護的是子樹中葉子節點的權值

【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; }