●BZOJ 3545 [ONTAK2010]Peaks(离线)
题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=3545
http://www.lydsy.com/JudgeOnline/problem.php?id=3551(同题,强制在线,题解)
题解:
最小生成树 Kruskal,线段树(合并),离线
首先把询问和边放在一起,按权值大小从小到大排序。
然后对每个点建一棵权值线段树,维护当前联通块里的海拔权值区间内的山的个数
然后按照 Kruskal 算法合并联通块,并且合并两个联通块对应的线段树(Merge操作看代码,感觉很暴力)。
然后对于一个枚举到的询问,其起点所在的联通块里的点一定是可以到达的,
所以就用线段树查询该联通块里的第k高的山就好了。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 100500 using namespace std; struct Oper{ int type,w,a,b; bool operator <(const Oper &rtm) const{ if(w!=rtm.w) return w<rtm.w; return type<rtm.type; } }O[MAXN*10]; struct SGT{ int rt[MAXN],ls[MAXN*50],rs[MAXN*50],cnt[MAXN*50],sz; void Modify(int &u,int l,int r,int p){ if(!u) u=++sz; if(l==r){cnt[u]++; return;} int mid=(l+r)>>1; cnt[u]++; if(p<=mid) Modify(ls[u],l,mid,p); else Modify(rs[u],mid+1,r,p); } int Merge(int u,int v){ if(!u||!v) return u+v; cnt[u]+=cnt[v]; ls[u]=Merge(ls[u],ls[v]); rs[u]=Merge(rs[u],rs[v]); return u; } int Query(int u,int l,int r,int p){ if(l==r) return l; int mid=(l+r)>>1; if(p<=cnt[rs[u]]) return Query(rs[u],mid+1,r,p); else return Query(ls[u],l,mid,p-cnt[rs[u]]); } }T; int Fa[MAXN],H[MAXN],ANS[5*MAXN]; int N,M,Q,Ont; void read(int &x){ static int f; static char ch; x=0; f=1; ch=getchar(); while(ch<'0'||'9'<ch){if(ch=='-') f=-1; ch=getchar();} while('0'<=ch&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} x=x*f; } int find(int x){ return x==Fa[x]?x:Fa[x]=find(Fa[x]); } int main(){ static int tmp[MAXN],tnt=0; read(N); read(M); read(Q); for(int i=1;i<=N;i++) Fa[i]=i,read(H[i]),tmp[++tnt]=H[i]; for(int i=1;i<=M;i++) read(O[++Ont].a),read(O[Ont].b),read(O[Ont].w),O[Ont].type=0; for(int i=1;i<=Q;i++) read(O[++Ont].a),read(O[Ont].w),read(O[Ont].b),O[Ont].type=i; sort(tmp+1,tmp+tnt+1); tnt=unique(tmp+1,tmp+tnt+1)-tmp-1; for(int i=1;i<=N;i++) H[i]=lower_bound(tmp+1,tmp+tnt+1,H[i])-tmp, T.Modify(T.rt[i],1,tnt,H[i]); sort(O+1,O+Ont+1); for(int i=1,f,fa,fb,p;i<=Ont;i++){ if(O[i].type){ f=find(O[i].a); if(T.cnt[T.rt[f]]<O[i].b) ANS[O[i].type]=-1; else p=T.Query(T.rt[f],1,tnt,O[i].b),ANS[O[i].type]=tmp[p]; } else{ fa=find(O[i].a); fb=find(O[i].b); if(fa==fb) continue; Fa[fb]=fa; T.rt[fa]=T.Merge(T.rt[fa],T.rt[fb]); } } for(int i=1;i<=Q;i++) printf("%d\n",ANS[i]); return 0; }
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas