[BZOJ 3551][ONTAK2010]Peaks加强版(Kruskal重构树+主席树)

mac2026-05-01  7

文章目录

题目分析代码

题目

Description 在Bytemountains有 N N N座山峰,每座山峰有他的高度 h i h_i hi。有些山峰之间有双向道路相连,共 M M M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有 Q Q Q组询问,每组询问询问从点 v v v开始只经过困难值小于等于 x x x的路径所能到达的山峰中第 k k k高的山峰,如果无解输出-1。

Input 第一行三个数 N N N M M M Q Q Q。 第二行 N N N个数,第 i i i个数为 h i h_i hi 接下来 M M M行,每行 3 3 3个数 a , b , c a,b,c a,b,c,表示从 a a a b b b有一条困难值为 c c c的双向路径。 接下来 Q Q Q行,每行三个数 v , x , k v,x,k v,x,k,表示一组询问。 v = v ⊕ lastans v=v \oplus \text{lastans} v=vlastans x = x ⊕ lastans x=x \oplus \text{lastans} x=xlastans k = k ⊕ lastans k=k \oplus \text{lastans} k=klastans。如果 lastans = − 1 \text{lastans}=-1 lastans=1则不变。

Output 对于每组询问,输出一个整数表示答案。

Sample Input

10 11 4 1 2 3 4 5 6 7 8 9 10 1 4 4 2 5 3 9 8 2 7 8 10 7 1 4 6 7 1 6 4 8 2 1 5 10 8 10 3 4 7 3 4 6 1 5 2 1 5 6 1 5 8 8 9 2

Sample Output

6 1 -1 8

Data Constraint N ≤ 1 0 5 N\leq 10^5 N105 M , Q ≤ 5 × 1 0 5 M,Q\leq5\times10^5 M,Q5×105 h i , c , x ≤ 1 0 9 h_i,c,x\leq10^9 hi,c,x109

Source By Sbullet

分析

建Kruskal重构树,然后就可以用倍增的方法 O ( log ⁡ n ) O(\log n) O(logn)求得“从点 v v v开始只经过困难值小于等于 x x x的路径所能到达的山峰”:

u u u v v v的,深度最小的,点权小于等于 x x x的,一个祖先;那么 u u u的子树的所有叶结点就是“从点 v v v开始只经过困难值小于等于 x x x的路径所能到达的山峰”。

然后查询这些叶结点中的区间第 k k k大,主席树即可。 (可持久化线段树的坑以后再填吧,,,,,)

代码

注意看一下注释的地方。

#include<bits/stdc++.h> using namespace std; inline int read(){ int x=0;bool f=0;char c=getchar(); while(c<'0'||c>'9') f|=c=='-',c=getchar(); while(c>='0'&&c<='9') x=x*10+(c^48),c=getchar(); return f?-x:x; } #define LOG 20 #define MAXN 100000 #define MAXM 500000 #define MAXP (2*MAXN) int N,M,Q; int H[MAXN+5]; struct Edge{ int u,v,w; }E[MAXM+5]; bool cmp(Edge i,Edge j){ return i.w<j.w; } int fa[MAXP+5]; void Init(int n){ for(int i=1;i<=n;i++) fa[i]=i; } int Find(int u){ return fa[u]==u?u:fa[u]=Find(fa[u]); } int Num[MAXN+5]; int Rev[MAXN+5]; map<int,int> ID; struct SegmentTree{ #define lch (T[i].ch[0]) #define rch (T[i].ch[1]) struct Node{ int cnt; int ch[2]; }T[MAXN*LOG*8+5]; int N,cnt,Root[MAXP+5]; void PushUp(int i){ T[i].cnt=T[lch].cnt+T[rch].cnt; } void Insert(int &i,int l,int r,int val,int Last){ //不能写这种,要在进入之前判,否则会被卡常!!!!! // if(val<l||val>r) // return; T[i=++cnt]=T[Last]; if(l==r){ T[i].cnt++; return; } int mid=(l+r)>>1; if(val<=mid) Insert(lch,l,mid,val,T[Last].ch[0]); else Insert(rch,mid+1,r,val,T[Last].ch[1]); PushUp(i); } int Query(int i,int l,int r,int kth,int Last){ if(l==r) return l; int mid=(l+r)>>1; int lcnt=T[lch].cnt-T[T[Last].ch[0]].cnt; if(lcnt>=kth) return Query(lch,l,mid,kth,T[Last].ch[0]); return Query(rch,mid+1,r,kth-lcnt,T[Last].ch[1]); } #undef lch #undef rch }T; #define lch (K[i].ch[0]) #define rch (K[i].ch[1]) struct KruskalNode{ int ch[2]; int w,l,r,id; }K[MAXP+5]; int id; vector<int> A; int Dep[MAXP+5]; bool vis[MAXP+5]; int Anc[MAXP+5][LOG+5]; void Build(int i,int fa,int dep){ Dep[i]=dep,vis[i]=1; if(lch&&rch){ Anc[lch][0]=Anc[rch][0]=i; Build(lch,i,dep+1); Build(rch,i,dep+1); K[i].l=K[lch].l,K[i].r=K[rch].r; } else{ K[i].l=K[i].r=++id; A.push_back(H[K[i].id]); } } #undef lch #undef rch int Query(int u,int lim,int kth){ for(int i=LOG;i>=0;i--) if(Anc[u][i]&&K[Anc[u][i]].w<=lim) u=Anc[u][i]; if(1<=kth&&kth<=K[u].r-K[u].l+1) return T.Query(T.Root[K[u].r],1,T.N,K[u].r-K[u].l-kth+2,T.Root[K[u].l-1]); return 0; } int main(){ N=read(),M=read(),Q=read(); for(int i=1;i<=N;i++) Num[i]=H[i]=read(); for(int i=1;i<=M;i++){ E[i].u=read(), E[i].v=read(), E[i].w=read(); } int cnt=0; sort(Num+1,Num+N+1); for(int i=1;i<=N;i++) if(!ID.count(Num[i])) Rev[ID[Num[i]]=++cnt]=Num[i]; for(int i=1;i<=N;i++) H[i]=ID[H[i]]; //离散化 T.N=cnt; cnt=N; Init(2*N); sort(E+1,E+M+1,cmp); for(int i=1;i<=N;i++) K[i].ch[0]=K[i].ch[1]=0,K[i].id=i; for(int i=1;i<=M;i++){ int u=E[i].u,v=E[i].v; int x=Find(u),y=Find(v); if(x!=y){ ++cnt; K[cnt].ch[0]=x; K[cnt].ch[1]=y; K[cnt].w=E[i].w; fa[x]=y,fa[y]=cnt; } } for(int i=cnt;i>=1;i--) if(!vis[i]){ int u=Find(i); Build(u,-1,1); } for(int i=0;i<int(A.size());i++) T.Insert(T.Root[i+1],1,T.N,A[i],T.Root[i]); for(int j=1;j<=LOG;j++) for(int i=1;i<=2*N;i++) Anc[i][j]=Anc[Anc[i][j-1]][j-1]; int Ans=0; while(Q--){ int u=read(),lim=read(),kth=read(); Ans=Rev[Query(u^Ans,lim^Ans,kth^Ans)]; printf("%d\n",Ans?Ans:-1); } }
最新回复(0)