P4197 Peaks [Kruskal 重构树 + 主席树]

传送门

从小到大排, kruskal重构 , 每次倍增找到值刚好小于等于要求的点 , 问题转化为子树内的第k大

静态子树k大, 不就是主席树吗

#include<bits/stdc++.h>
#define N 200050
#define M 500050
using namespace std;

int first[N],next[M],to[M],tot;

struct Node{int u,v,w;}E[M];
bool cmp(Node a,Node b){return a.w<b.w;}

struct Tree{int ls,rs,val;}t[N*40];
int rt[N],siz,res;

int n,m,q,cnt,h[N],b[N];
int father[N]; 
int find(int x){return x==father[x]?x:father[x]=find(father[x]);}
int fa[N][22],val[N],st[N],ed[N],sign;

int read(){
	int cnt=0; char ch=0;
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
	return cnt;
}

void add(int x,int y){next[++tot]=first[x],first[x]=tot,to[tot]=y;}

void Kruskal(){
	sort(E+1,E+m+1,cmp); cnt=n;
	for(int i=1;i<=m;i++){
		int x=E[i].u , y=E[i].v;
		int fx = find(x), fy = find(y);
		if(fx!=fy){
			val[++cnt] = E[i].w;
			father[fx] = father[fy] = cnt;
			add(cnt,fx); add(cnt,fy);
		}
	} 
}

/*----------------------------------主席树-------------------------------------*/
void Build(int &x,int l,int r){
	x=++res;
	if(l==r){ t[x].val = 0; return;}
	int mid = (l+r) >> 1;
	Build(t[x].ls, l, mid);
	Build(t[x].rs, mid+1, r);
} 
void Insert(int &x,int last,int l,int r,int pos){
	x = ++res;
	t[x].ls = t[last].ls, t[x].rs = t[last].rs;
	t[x].val = t[last].val + 1; 
	if(l==r) return;
	int mid = (l+r) >> 1;
	if(pos<=mid) Insert(t[x].ls, t[last].ls, l, mid, pos);
	else Insert(t[x].rs, t[last].rs, mid+1, r, pos);
}
int Quary(int x,int y,int l,int r,int k){
	if(l==r) return l;
	int mid = (l+r) >> 1;
	int tmp = t[t[y].rs].val - t[t[x].rs].val;
	if(tmp >= k) return Quary(t[x].rs,t[y].rs,mid+1,r,k);
	else return Quary(t[x].ls,t[y].ls,l,mid,k-tmp); 
}
void dfs(int u,int f){
	fa[u][0] = f;
	for(int i=1;i<=20;i++)
		fa[u][i] = fa[fa[u][i-1]][i-1];
	st[u] = ++sign;
	if(u<=n) Insert(rt[sign],rt[sign-1],1,siz,h[u]);
	else rt[sign] = rt[sign-1];
	
	for(int i=first[u];i;i=next[i]){
		int t=to[i]; dfs(t,u);
	} ed[u] = sign;
}
int main(){
	n=read(),m=read(),q=read();
	for(int i=1;i<=n*2;i++) father[i]=i;
	for(int i=1;i<=n;i++) h[i] = b[i] = read();
	sort(b+1,b+n+1); siz = unique(b+1,b+n+1) - (b+1);
	for(int i=1;i<=n;i++) h[i] = lower_bound(b+1,b+siz+1,h[i]) - b;
	
	for(int i=1;i<=m;i++){
		E[i].u=read(),E[i].v=read(),E[i].w=read();
	} Kruskal();  Build(rt[0],1,siz);
	dfs(cnt,0);
	while(q--){
		int v=read(),x=read(),k=read();
		for(int i=20;i>=0;i--)
			if(fa[v][i] && val[fa[v][i]]<=x) v = fa[v][i];
		int tmp1 = rt[st[v]-1], tmp2 = rt[ed[v]];
		if(t[tmp2].val - t[tmp1].val < k){ printf("-1\n"); continue;} 
		int ans = Quary(tmp1, tmp2, 1, siz, k);
		printf("%d\n",b[ans]);
	} return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值