Luogu4197 Peaks

挺有意思的一个题

Description

link

有一个无向图,点有点权,边有边权

询问每个点出发经过边权不超过定值的第 (k) 大点权

(n le 10^5 m le 5 imes 10^5)

Solution

我们离线所有操作之后按照边的长度排序,之后线段树合并的基操就完事了

前半句想到了这题就没意思了

Code

#include<bits/stdc++.h>
using namespace std;
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=2e6+10,M=1e5+10;
	struct node{
		int u,v,w,opt,id;
		bool operator<(const node &a) const{return w==a.w?opt<a.opt:w<a.w;}
	}s[N];
	#define fr(p) s[p].u
	struct tree{
		int ls,rs,sum;
		#define sum(p) t[p].sum
		#define ls(p) t[p].ls
		#define rs(p) t[p].rs
	}t[N<<2];
	int n,m,q,h[M],b[M],tot,cnt,fa[N],rt[N],ans[M*5];
	inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
	inline void push_up(int p){return sum(p)=sum(ls(p))+sum(rs(p)),void();}
	inline void update(int &p,int l,int r,int x)
	{
		if(!p) p=++tot; if(l==r) return sum(p)++,void();
		int mid=(l+r)>>1;
		if(x<=mid) update(ls(p),l,mid,x); else update(rs(p),mid+1,r,x);
		return push_up(p);
	}
	inline int merge(int x,int y,int l,int r)
	{
		if(!x||!y) return x+y;
		if(l==r) return sum(x)+=sum(y),x;
		int mid=(l+r)>>1,p=++tot;
		ls(p)=merge(ls(x),ls(y),l,mid); rs(p)=merge(rs(x),rs(y),mid+1,r);
		return push_up(p),p;
	}
	inline int query(int p,int l,int r,int k)
	{
		if(l==r) return l;
		int mid=(l+r)>>1,tmp=sum(rs(p));
		if(tmp>=k) return query(rs(p),mid+1,r,k); 
		else return query(ls(p),l,mid,k-tmp);
	}
	signed main()
	{
		n=read(); m=read(); q=read();
		for(int i=1;i<=n;++i)
		{
			h[i]=read(); b[++cnt]=h[i];
		}
		sort(b+1,b+cnt+1); 
		cnt=unique(b+1,b+cnt+1)-b-1; 
		for(int i=1;i<=n;++i) 
		{
			h[i]=lower_bound(b+1,b+cnt+1,h[i])-b;
			update(rt[i],1,cnt,h[i]);
			fa[i]=i;
		}
		for(int i=1;i<=m;++i)
		{
			s[i].u=read(); s[i].v=read(); s[i].w=read(); s[i].opt=0;
		}
		for(int i=1;i<=q;++i) s[i+m].id=i,s[i+m].u=read(),s[i+m].w=read(),s[i+m].v=read(),s[i+m].opt=1;
		sort(s+1,s+m+q+1);
		for(int i=1;i<=m+q;++i) 
		{
			if(!s[i].opt)
			{
				int ax=find(s[i].u),ay=find(s[i].v);
				if(ax==ay) continue;
				fa[ax]=ay;
				rt[ay]=merge(rt[ay],rt[ax],1,cnt);
			}
			else
			{
				fr(i)=find(fr(i)); 
				if(sum(rt[fr(i)])<s[i].v) ans[s[i].id]=-1;
				else ans[s[i].id]=b[query(rt[fr(i)],1,cnt,s[i].v)];
			}
		}
		
		for(int i=1;i<=q;++i) printf("%d
",ans[i]);
		return 0;
	}
}
signed main(){return yspm::main();}

Riview

在在线处理问题的时候可以考虑离线之后这个题有啥性质

尤其是排序有大小关系的那种,最近没少做离线排序题

原文地址:https://www.cnblogs.com/yspm/p/12721251.html