我们如果首先求出了最小生成树,那么在询问的时候去掉所有边权>x的边,那么剩下的和v相连的就是可以走到的山峰。
那么考虑在并查集的时候做一点科(shou)技(jiao),比如现在要合并u和v所在的连通块,边权为t,那么显然u中所有点到v中所有点的路径中的最大边权为t,那么新建一个点p,连p->u和p->v且p的点权为t。那么n-1合并之后得到了一颗有n的叶子节点的树,那么两个点x->y的路径中的最大值即它们lca的点权。
这样在操作的时候就可以找到v的最上面的一个<=x的祖先(显然点权随着深度递增),那么这个祖先的子树中的所有点就是v所能到达的点。因此只需要维护某一个点的子树的信息即可。
求子树中第k小点,可以用dfs序+主席树;也可以每个点保存一颗线段树然后合并。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 200005 #define M 500005 using namespace std; int n,m,pt,cnt,dfsclk,tot,trtot,bin[25],a[N],num[N],fa[N],d[N],anc[N][17],fst[N],pnt[M],nxt[M]; int pos[N][2],id[N],rt[N],ls[4000005],rs[4000005],sum[4000005]; struct edg{ int x,y,z; }e[M]; int read(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } int getfa(int x){ return (x==fa[x])?x:fa[x]=getfa(fa[x]); } void add(int x,int y){ pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot; } int find(int x){ int l=0,r=cnt,mid; while (l<r){ mid=(l+r)>>1; if (num[mid]<x) l=mid+1; else r=mid; } return l; } void dfs(int x){ pos[x][0]=pos[x][1]=++dfsclk; id[dfsclk]=x; int p,i; for (i=1; bin[i]<=d[x]; i++) anc[x][i]=anc[anc[x][i-1]][i-1]; for (p=fst[x]; p; p=nxt[p]){ int y=pnt[p]; anc[y][0]=x; d[y]=d[x]+1; dfs(y); pos[x][1]=pos[y][1]; } } int getanc(int x,int t){ int i; if (!t) return x; for (i=16; i>=0; i--){ if (bin[i]<=d[x] && a[anc[x][i]]<=t) x=anc[x][i]; } return x; } void ins(int l,int r,int x,int &y,int k){ y=++trtot; sum[y]=sum[x]+1; if (l==r) return; int mid=(l+r)>>1; if (k<=mid){ rs[y]=rs[x]; ins(l,mid,ls[x],ls[y],k); } else{ ls[y]=ls[x]; ins(mid+1,r,rs[x],rs[y],k); } } int qry(int x,int y,int z){ int l=1,r=cnt,mid,tmp; x=rt[x-1]; y=rt[y]; if (sum[y]-sum[x]<z) return -1; z=sum[y]-sum[x]-z+1; while (l<r){ mid=(l+r)>>1; tmp=sum[ls[y]]-sum[ls[x]]; if (tmp>=z){ x=ls[x]; y=ls[y]; r=mid; } else{ x=rs[x]; y=rs[y]; z-=tmp; l=mid+1; } } return num[l]; } bool cmp(edg u,edg v){ return u.z<v.z; } int main(){ n=read(); m=read(); int i,cas=read(); bin[0]=1; for (i=1; i<=17; i++) bin[i]=bin[i-1]<<1; for (i=1; i<=n; i++) a[i]=num[i]=read(); sort(num+1,num+n+1); cnt=1; for (i=2; i<=n; i++) if (num[i]!=num[cnt]) num[++cnt]=num[i]; for (i=1; i<=n; i++) a[i]=find(a[i]); for (i=1; i<=m; i++){ e[i].x=read(); e[i].y=read(); e[i].z=read(); } sort(e+1,e+m+1,cmp); pt=n; int k,x,y; for (i=1; i<(n<<1); i++) fa[i]=i; for (i=1; i<=m; i++){ x=getfa(e[i].x); y=getfa(e[i].y); if (x!=y){ fa[x]=fa[y]=++pt; a[pt]=e[i].z; add(pt,x); add(pt,y); if (pt+1==(n<<1)) break; } } for (i=1; i<=n; i++){ x=getfa(i); if (!pos[x][0]) dfs(x); } for (i=1; i<=pt; i++) if (id[i]<=n) ins(1,cnt,rt[i-1],rt[i],a[id[i]]); else rt[i]=rt[i-1]; int ans=0; while (cas--){ x=read()^ans; y=read()^ans; k=read()^ans; x=getanc(x,y); printf("%d\n",ans=qry(pos[x][0],pos[x][1],k)); if (ans<0) ans=0; } return 0; }
by lych
2016.3.30