【BZOJ3551】【洛谷P4197】—Peaks加强版(Kruscal重构树+主席树)

BZOJ传送门

洛谷传送门(注意洛谷上并没有要求强制在线)

这道题有毒吧

洛谷ACAC,本机ACAC,然而BZOJBZOJ上莫名TLETLE??

fuckfuck


考虑到有多次询问瓶颈路
我们构建KruscalKruscal重构树

由于重构树特殊的性质
树上一个点的子树的权值必定都是比这个点小的

那么对于每次询问的vv,我们考虑找到它到根路径上第一个权值大于等于xx的点
这个可以用树上倍增实现

那现在的问题就变成了在一个点的子树中,查询所有叶子节点的第kk
这个对于dfsdfs序中叶子节点建主席树就解决了

虽然感觉实现有点难写

不过有个小技巧:我们可以发现重构树上每个非叶节点必定有2个儿子

那么我们可以直接对每个点维护左右儿子,就不需要建邻接表

具体细节可以看代码(丑到窒息)

还有重构树可能是不连通的

这个情况要判断

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=500005;
const int M=1000005;
const int Log=22;
int n,m,q,h[N],s[N],ans=-1;
namespace Kruscal{
	struct edge{
		int u,v,w;
	}e[N];
	int adj[N<<1],nxt[M<<2],to[M<<2],val[N<<1],tot,cnt,lc[N<<1],rc[N<<1],f[N<<1][Log],fa[N];
	inline bool comp(const edge &a,const edge &b){
		return a.w<b.w;
	}
	inline void addedge(int u,int v){
		nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
	}
	int find(int x){
		return fa[x]==x?x:fa[x]=find(fa[x]);
	}
	inline void kruscal(){
		sort(e+1,e+m+1,comp);
		for(int i=1;i<=m;i++){
			int f1=find(e[i].u),f2=find(e[i].v);
			if(f1!=f2){
				fa[f1]=fa[f2]=fa[++tot]=tot;
				f[f1][0]=f[f2][0]=tot;
				lc[tot]=f1,rc[tot]=f2;
				val[tot]=e[i].w;
			}
		}
	}
}
namespace JZMS_Tree{
	#define mid ((l+r)>>1)
	#define lc(u) son[u][0]
	#define rc(u) son[u][1]
	int rt[N<<3],sum[7000000],num,son[7000000][2];
	void insert(int &u,int r1,int l,int r,int pos){
		u=++num;
		sum[u]=sum[r1]+1;
		if(l==r)return;
		lc(u)=lc(r1),rc(u)=rc(r1);
		if(pos<=mid)insert(lc(u),lc(r1),l,mid,pos);
		else insert(rc(u),rc(r1),mid+1,r,pos);
	}
	int query(int r1,int r2,int l,int r,int k){
		if(l==r)return s[l];
		int t=sum[rc(r1)]-sum[rc(r2)];
		if(t>=k)return query(rc(r1),rc(r2),mid+1,r,k);
		else return query(lc(r1),lc(r2),l,mid,k-t);
	}
	#undef lc
	#undef rc
}
namespace Pre_operator{
	using namespace Kruscal;
	using namespace JZMS_Tree;
	int in[N<<1],out[N<<1];
	int dfn;
	void dfs(int u){
		for(int i=1;i<=20;i++)
			f[u][i]=f[f[u][i-1]][i-1];
		if(u<=n){
			in[u]=out[u]=++dfn;
			insert(rt[dfn],rt[dfn-1],1,n,h[u]);
			return;
		}
		dfs(lc[u]),dfs(rc[u]);
		in[u]=in[lc[u]],out[u]=out[rc[u]];
	}
	int get(int u,int k){
		for(int i=20;i>=0;i--){
			if(f[u][i]&&val[f[u][i]]<=k)
				u=f[u][i];
		}
		return u;
	}
}
using namespace Pre_operator;
int main(){
	tot=n=read(),m=read(),q=read();
	for(int i=1;i<=n;i++)h[i]=s[i]=read();
	sort(s+1,s+n+1);
	for(int i=1;i<=n;i++)
		h[i]=lower_bound(s+1,s+n+1,h[i])-s;
	for(int i=1;i<=m;i++){
		e[i].u=read(),e[i].v=read(),e[i].w=read();
	}
	for(int i=1;i<=n;i++)fa[i]=i;
	kruscal();
	for(int i=tot;i;i--)
	if(!in[i])dfs(i);
	dfs(find(1));
	for(int i=1;i<=q;i++){
		int v=read(),x=read(),k=read();
		if(ans!=-1)v^=ans,x^=ans,k^=ans;
		v=get(v,x);
		if(out[v]-in[v]+1<k)ans=-1;
		else ans=query(rt[out[v]],rt[in[v]-1],1,n,k);
		cout<<ans<<'\n';
	}
}
posted @ 2019-01-26 21:50  Stargazer_cykoi  阅读(168)  评论(0编辑  收藏  举报