BZOJ3545 [ONTAK2010]Peaks kruskal 并查集 主席树 dfs序
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ3545
题意概括
Description
在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
Input
第一行三个数N,M,Q。
第二行N个数,第i个数为h_i
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。
Output
对于每组询问,输出一个整数表示答案。
题解
这题卡常,要读入优化。
代码
#include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> using namespace std; const int N=100005,M=500005,S=N*2,Inf=1e9+5; bool isd(char ch){ return '0'<=ch&&ch<='9'; } void read(int &x){ x=0; char ch=getchar(); while (!isd(ch)) ch=getchar(); while (isd(ch)) x=(x<<1)+(x<<3)+ch-48,ch=getchar(); } struct Edge{ int x,y,z; void Read(){ read(x),read(y),read(z); } }e[M]; bool cmpz(Edge a,Edge b){ return a.z<b.z; } struct MQset{//并查集 int cnt,fa[N*2]; void clear(){cnt=0;} int getf(int k){return fa[k]==k?k:fa[k]=getf(fa[k]);} void push(int x){fa[x]=x;} void merge(int x,int y){fa[getf(x)]=getf(y);} }s; int n,m,q,h[N]; int fa[S],lc[S],rc[S],val[S],cnt; int anst[S][20],time,in[S],out[S],dfn[S]; void dfs(int rt){ anst[rt][0]=fa[rt]; for (int i=1;i<20;i++) anst[rt][i]=anst[anst[rt][i-1]][i-1]; in[rt]=time; if (!lc[rt]) dfn[++time]=rt; else dfs(lc[rt]),dfs(rc[rt]); out[rt]=time; } const int SIZE=N*2*20*2; int Ha[N],hs; int ls[SIZE],rs[SIZE],sum[SIZE],total,root[N]; void LSH(){ int hs_=1; sort(Ha+1,Ha+hs+1); for (int i=2;i<=hs;i++) if (Ha[i]!=Ha[i-1]) Ha[++hs_]=Ha[i]; hs=hs_; } int find(int x){ return lower_bound(Ha+1,Ha+hs+1,x)-Ha; } void build(int &rt,int L,int R){ rt=++total; sum[rt]=0; if (L==R) return; int mid=(L+R)>>1; build(ls[rt],L,mid); build(rs[rt],mid+1,R); } void add(int prt,int &rt,int L,int R,int pos){ rt=++total; if (L==R){ sum[rt]=sum[prt]+1; return; } int mid=(L+R)>>1; if (pos<=mid) add(ls[prt],ls[rt],L,mid,pos),rs[rt]=rs[prt]; else add(rs[prt],rs[rt],mid+1,R,pos),ls[rt]=ls[prt]; sum[rt]=sum[ls[rt]]+sum[rs[rt]]; } int query(int prt,int rt,int L,int R,int k){ if (L==R) return Ha[L]; int Rz=sum[rs[rt]]-sum[rs[prt]]; int mid=(L+R)>>1; if (Rz>=k) return query(rs[prt],rs[rt],mid+1,R,k); else return query(ls[prt],ls[rt],L,mid,k-Rz); } int find(int x,int v){ for (int i=19;i>=0;i--) if (val[anst[x][i]]<=v) x=anst[x][i]; return x; } int main(){ read(n),read(m),read(q); for (int i=1;i<=n;i++) read(h[i]),Ha[i]=h[i]; hs=n; LSH(); for (int i=1;i<=n;i++) h[i]=find(h[i]); for (int i=1;i<=m;i++) e[i].Read(); sort(e+1,e+m+1,cmpz); s.clear(); for (int i=1;i<=n;i++){ s.push(i); fa[i]=lc[i]=rc[i]=val[i]=0; } cnt=n; for (int i=1;i<=m;i++){ int x=e[i].x,y=e[i].y,z=e[i].z; x=s.getf(x),y=s.getf(y); if (x==y) continue; s.push(++cnt); fa[x]=fa[y]=cnt; fa[cnt]=0,lc[cnt]=x,rc[cnt]=y,val[cnt]=z; s.fa[x]=s.fa[y]=cnt; } val[0]=Inf; time=0; dfs(cnt); build(root[0],1,n); for (int i=1;i<=n;i++) add(root[i-1],root[i],1,n,h[dfn[i]]); for (int i=1;i<=q;i++){ int v,x,k,y; read(v),read(x),read(k); y=find(v,x); if (out[y]-in[y]<k) puts("-1"); else printf("%d\n",query(root[in[y]],root[out[y]],1,n,k)); } return 0; }