[bzoj3551] Peaks加强版

本文深入探讨了Kruskal重构树算法在[bzoj3551] Peaks加强版问题中的应用,通过详细解释代码实现过程,展示了如何利用Kruskal算法进行树的重构,并解决特定查询问题。文章涵盖了链接查找、路径压缩、段树更新和查询等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[bzoj3551] Peaks加强版


Kruskal重构树。轻微卡常。

  • 代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
const int M=1e6+5;
struct edge{
	int u,v,val;
	bool operator<(const edge b)const{return val<b.val;}
}e[M];
int n,m,q;
int hh[N],linker[N],fa[N],par[N];
int findlink(int x){return linker[x]==x?x:linker[x]=findlink(linker[x]);}
int findpar(int x){return par[x]==x?par[x]:par[x]=findpar(par[x]);}
int anc[N][20],mx[N][20],val[N];
int root,ch[N][2],num,id[N],rt[N];
int ll[N],rr[N];
struct SegT{
	int lch[N*12],rch[N*12],t[N*12],cnt;
	inline void ins(int &x,int pst,int l,int r,int pos,int sum){
		if(!x)x=++cnt;
		int mid=(l+r)>>1;
		t[x]=t[pst]+sum;
		if(l==r){return;}
		if(pos>mid)ins(rch[x],rch[pst],mid+1,r,pos,sum),lch[x]=lch[pst];
		else ins(lch[x],lch[pst],l,mid,pos,sum),rch[x]=rch[pst];
	}
	inline int qry(int x,int y,int l,int r,int sum){
		int tx=t[x]-t[y];
		int mid=(l+r)>>1;
		if(sum>tx)return -1;
		if(l==r)return l;
		if(t[rch[x]]-t[rch[y]]>=sum)
			return qry(rch[x],rch[y],mid+1,r,sum);
		else
			return qry(lch[x],lch[y],l,mid,sum-(t[rch[x]]-t[rch[y]]));
	}
}T;
inline void dfs(int x){
	if(x<=n){
		ll[x]=rr[x]=num+1;
		id[x]=++num;
		T.ins(rt[num],rt[num-1],1,n,hh[x],1);
		return ;
	}
	dfs(ch[x][0]);
	dfs(ch[x][1]);
	ll[x]=ll[ch[x][0]];
	rr[x]=rr[ch[x][1]];
}
typedef pair<int,int> pii;
int read(){
	char x=0;int ret=0;
	while(x<'0'||x>'9')x=getchar();
	while(x>='0'&&x<='9')ret=ret*10+x-'0',x=getchar();
	return ret;
}
pii rk[N];
int main()
{
	n=read(),m=read(),q=read();
	root=n;
	for(int i=1;i<=n;i++){
		hh[i]=read();
		rk[i]=pii(hh[i],i);
	}
	sort(rk+1,rk+n+1);
	for(int i=1;i<=n;i++){
		hh[rk[i].second]=i;
	}
	for(int i=1;i<=m;i++){
		e[i].u=read(),e[i].v=read(),e[i].val=read();
	}
	for(int i=1;i<=n*2+2;i++)linker[i]=i,par[i]=i;
	sort(e+1,e+m+1);
	for(int i=1;i<=m;i++){
		int u=e[i].u,v=e[i].v;
		int x=findlink(u),y=findlink(v);
		if(x^y){
			linker[x]=y;
			int uu=findpar(u),vv=findpar(v);
			++root;
			val[root]=e[i].val;
			par[uu]=par[vv]=root;
			fa[uu]=fa[vv]=root;
			ch[root][0]=uu;ch[root][1]=vv;
		}
	}
	dfs(root);
	for(int i=1;i<=root;i++){
		anc[i][0]=fa[i];
		mx[i][0]=val[fa[i]];
	}
	int tp=1;
	for(int i=1;1<<i<=root;i++){
		tp=i;
		for(int j=1;j<=root;j++){
			anc[j][i]=anc[anc[j][i-1]][i-1];
		}
	}
	int lastans=0;
	while(q--){
		int v,x,k;
		v=read(),x=read(),k=read();
		v^=lastans,x^=lastans,k^=lastans;
		for(int i=tp;~i;i--){
			if(anc[v][i]){
				if(val[anc[v][i]]<=x){
					v=anc[v][i];
				}
			}
		}
		int ans=T.qry(rt[rr[v]],rt[ll[v]-1],1,n,k);
		if(ans!=-1)ans=rk[ans].first;
		printf("%d\n",ans);
		if(ans==-1)ans=0;
		lastans=ans;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值