SPOJ 10628 Count on The tree .. .. 主席树

1 篇文章 0 订阅
1 篇文章 0 订阅


先离散化出 cnt个不同的数,再以这cnt个不同的数来建立主席树,主席树记录的是某节点的数量,

这样就可以通过树的加减操作,来判断< a[num] 的数有多少个了。。

这题只用从根序列开始,记录到每个点的线段树

DFS从根开始构造序列

可以知道  dist[a,b]  = dist[a,root] + dist[b,root] - dist[ lca,root] - dist[fa[lca] , root];

这就是Query的内容了。

ORZ

//tpl
//ipqhjjybj_tpl.h
//header.h
#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>
#include <queue>

#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define rep(i,j,k) for(int i = j; i < k;i++)
#define nrep(i,j,k) for(int i = j; i <= k;i++)

using namespace std;

const int N = 111111;
const int INF = 0x3f3f3f3f;
const int maxs = 20;
int a[N],b[N],fa[N],root[N],ls[N*20],rs[N*20],deep[N];
int sum[N*20];
int flca[N][20];
vector<int> g[N];
int tot;

void build(int l,int r,int &rt){
	rt = tot++;
	sum[rt] = 0;
	if(l>=r)return;
	int mid = (l+r)>>1;
	build(l,mid,ls[rt]);
	build(mid+1,r,rs[rt]);
}
void update(int last,int p,int l,int r,int &rt){
	rt = tot++;
	ls[rt] = ls[last], rs[rt] = rs[last];
	sum[rt] = sum[last]+1;
	if(l>=r) return;
	int mid = (l+r)>>1;
	if(p <= mid){
		update(ls[last],p,l,mid,ls[rt]);
	}else{
		update(rs[last],p,mid+1,r,rs[rt]);
	}
}
int query(int left_rt,int right_rt,int lca,int flc,int l,int r,int k){
	if(l>=r) return l;
	int mid = (l+r)>>1;
	int cnt = sum[ls[left_rt]] + sum[ls[right_rt]] - sum[ls[lca]] - sum[ls[flc]];
	if(k <= cnt)
		return query(ls[left_rt],ls[right_rt],ls[lca],ls[flc],l,mid,k);
	else return query(rs[left_rt],rs[right_rt],rs[lca],rs[flc],mid+1,r,k-cnt);
}
int getlca(int u,int v){
	if(deep[u] > deep[v]) swap(u,v);
	if(deep[u] < deep[v]){
		int del = deep[v] - deep[u];
		for(int i = 0;i < maxs;i++)
			if(del & (1<<i)) v = flca[v][i];
	}
	if(u!=v){
		for(int i = maxs-1; i >= 0;i--)
			if(flca[u][i] != flca[v][i])
				u = flca[u][i], v = flca[v][i];
		u = flca[u][0];
	}
	return u;
}
void dfs(int u,int f,int n){
	flca[u][0] = fa[u] = f , deep[u] = deep[f] + 1;	
	for(int i = 1;i < maxs;i++) {
		flca[u][i] = flca[flca[u][i-1]][i-1];
		//printf("flca[%d][%d]=%d\n",u,i,flca[u][i]);
	}
	update(root[f],a[u],1,n,root[u]);
	for(int i = 0;i < g[u].size();i++){
		int v = g[u][i];
		if(v != f)
			dfs(v,u,n);
	}
}
int main(){
	int n,m;
	int u,v,w;
	while(scanf("%d %d",&n,&m)!=EOF){
		nrep(i,1,n) g[i].clear();
		nrep(i,1,n) scanf("%d",a+i);
		memcpy(b,a,sizeof(a));
		sort(b+1,b+1+n);
		int cnt = unique(b+1,b+1+n) - b-1;
		nrep(i,1,n){
			a[i] = lower_bound(b+1,b+cnt+1,a[i])-b;
			//printf("a[%d]=%d\n",i,a[i]);
		}
		rep(i,1,n){
			scanf("%d %d",&u,&v);
			g[u].push_back(v) , g[v].push_back(u);
		}
		tot = 0;
		build(1,cnt,root[0]);
		deep[0] = 0;
		dfs(1,0,cnt);
		nrep(zz,1,m){
			scanf("%d %d %d",&u,&v,&w);
			int lca = getlca(u,v);
			int ans = query(root[u],root[v],root[lca],root[fa[lca]],1,cnt,w);

			printf("%d\n",b[ans]);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值