1. 程式人生 > >Kruskal重構樹+Dfs序+ 樹上倍增

Kruskal重構樹+Dfs序+ 樹上倍增

描述

在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之間有雙向道路相連,共M條路徑,每條路徑有一個困難值,這個值越大表示越難走,現在有Q組詢問,每組詢問詢問從點v開始只經過困難值小於等於x的路徑所能到達的山峰中第k高的山峰,如果無解輸出-1。

輸入

第一行三個數N,M,Q。

第二行N個數,第i個數為h_i

接下來M行,每行3個數a b c,表示從a到b有一條困難值為c的雙向路徑。

接下來Q行,每行三個數v x k,表示一組詢問。v=v xor lastans,x=x xor lastans,k=k xor lastans。如果lastans=-1則不變。

輸出

對於每組詢問,輸出一個整數表示答案。

Analysis

只能經過困難值小於等於K的路徑,這限制了走的路徑權值 而我們又學過Kruskal重構樹,很容易發現,重新構建出來的樹,其非葉子節點的權值就能很好地詮釋限制 由於非葉子節點的權值是從下往上單調不減的,對於詢問的起點,我們找到最上面的一個點xx,使其權值恰好小於等於KK,那麼我們可以走到的點,就是以xx為根的子樹中的葉子節點了。這個尋找可以樹上倍增 然後我們需要求第k大的樹,就用可持久化線段樹(主席樹)解決即可 (注意是第k大,不是第k小,平時的模板要稍微變一下)

Code

空間是瞎開的,反正不會MLE,也不會RE就是了

#include<bits/stdc++.h>
#define in read() #define M 500009 #define NN 200009 using namespace std; inline int read(){ char ch;int f=1,res=0; while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1; while(ch>='0'&&ch<='9'){ res=(res<<3)+(res<<1)+ch-'0'; ch=getchar(); } return f==1?res:-res; } char xxx;
int lastans=-1,n,m,q,N,idx=0; int fa[NN],h[NN],val[NN],tmp[NN],rt[NN<<2]; int nxt[M],to[M],head[NN],ecnt=0; int dep[NN],F[NN][22],maxn[NN][22]; int vis[NN],que[NN<<2],top=0; int S[NN],T[NN]; int tot=0,sze[NN*25],son[NN*25][2]; struct node{int u,v,w;}p[M]; char yyy; inline void add(int x,int y){ nxt[++ecnt]=head[x];head[x]=ecnt;to[ecnt]=y; } inline bool cmp(const node &a,const node &b){return a.w<b.w;} inline int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);} inline void dfs(int x){ que[++top]=x;vis[x]=1; for(int i=1;(1<<i)<=dep[x];++i) F[x][i]=F[F[x][i-1]][i-1],maxn[x][i]=max(maxn[x][i-1],maxn[F[x][i-1]][i-1]); for(int e=head[x];e;e=nxt[e]){ int y=to[e]; dep[y]=dep[x]+1;maxn[y][0]=val[x];F[y][0]=x; dfs(y); } if(x>n) que[++top]=x; } inline void update(int &p,int last,int l,int r,int v){ p=++tot;sze[p]=sze[last]+1; if(l==r) return; son[p][0]=son[last][0];son[p][1]=son[last][1]; int mid=l+r>>1; if(v<=mid) update(son[p][0],son[last][0],l,mid,v); else update(son[p][1],son[last][1],mid+1,r,v); } inline int query(int x,int y,int l,int r,int k){ if(l==r) return l; int mid=l+r>>1; if(sze[son[y][0]]-sze[son[x][0]]>=k) return query(son[x][0],son[y][0],l,mid,k); else return query(son[x][1],son[y][1],mid+1,r,k-sze[son[y][0]]+sze[son[x][0]]); } inline void kruskal(){ sort(p+1,p+m+1,cmp); int num=0;idx=n; for(int i=1;i<=(n<<1);++i) fa[i]=i; for(int i=1;i<=m;++i){ int x=p[i].u,y=p[i].v; int fx=getfa(x),fy=getfa(y); if(fx!=fy){ fa[fx]=fa[fy]=++idx; val[idx]=p[i].w; add(idx,fx);add(idx,fy); num++; if(num==n-1) break; } } for(int i=1;i<=n;++i) if(!vis[i]) dfs(getfa(i)); for(int i=1;i<=top;++i){ int u=que[i]; if(u<=n) update(rt[i],rt[i-1],1,n,h[u]); else{ rt[i]=rt[i-1]; if(!S[u]) S[u]=i; else T[u]=i; } } } inline int find(int x,int v){ for(int i=20;i>=0;--i) if(dep[x]>=(1<<i)&&maxn[x][i]<=v) x=F[x][i]; return x; } int main(){ n=in;m=in;q=in; for(int i=1;i<=n;++i) h[i]=tmp[i]=in; for(int i=1;i<=m;++i) p[i].u=in,p[i].v=in,p[i].w=in; sort(tmp+1,tmp+n+1);//n=unique(tmp+1,tmp+N+1)-tmp-1; for(int i=1;i<=n;++i) h[i]=lower_bound(tmp+1,tmp+n+1,h[i])-tmp; kruskal(); while(q--){ int v=in,x=in,k=in; if(~lastans) v^=lastans,x^=lastans,k^=lastans; int RT=find(v,x); int l=rt[S[RT]],r=rt[T[RT]]; if(sze[r]-sze[l]<k) { printf("-1\n"); lastans=-1; } else{ lastans=tmp[query(l,r,1,n,sze[r]-sze[l]-k+1)]; printf("%d\n",lastans); } } return 0; }