挺有意思的一个题
Description
有一个无向图,点有点权,边有边权
询问每个点出发经过边权不超过定值的第 (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
在在线处理问题的时候可以考虑离线之后这个题有啥性质
尤其是排序有大小关系的那种,最近没少做离线排序题