CF893F Subtree Minimum Query [主席树]

传送门

比较容易想到, 按dep建主席树, 然后在dep[u]-1 ---- dep[u]+k区间的数中查询dfs序在st[u] -- ed[u] 之间的最小值

我开始想, 最小值不满足区间减法怎么办, 然后又想, <= dep[u] - 1的点dfs序能在 st[u] --- ed[u] 之间吗?

一个比较容易错的地方就是, 按dep建, 必须用一个vector把每层的点存下来一起建, 然后就是裸的主席树了

#include<bits/stdc++.h>
#define N 200050
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
	while(isdigit(ch)) cnt = (cnt<<3) + (cnt<<1) + (ch-'0'), ch = getchar();
	return cnt * f;
}
const int inf = 0x3fffffff;
vector<int> v[N]; int mx;
int first[N], nxt[N], to[N], tot;
void add(int x, int y){ nxt[++tot] = first[x], first[x] = tot, to[tot] = y;}
int n, root, m, a[N], rt[N], cnt, lastans;
int dep[N], st[N], ed[N], sign;
struct Node{ int ls, rs, val;} t[N * 30];
void Build(int &x, int l, int r){
	x = ++cnt; t[x].val = inf; if(l == r) 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, int val){
	x = ++cnt; t[x] = t[last]; t[x].val = min(t[x].val, val); if(l == r) return;
	int mid = (l+r) >> 1; 
	if(pos <= mid) Insert(t[x].ls, t[last].ls, l, mid, pos, val);
	else Insert(t[x].rs, t[last].rs, mid+1, r, pos, val);
}
int Quary(int x, int l, int r, int L, int R){
	if(L<=l && r<=R) return t[x].val; int mid = (l+r) >> 1, ans = inf;
	if(L<=mid) ans = min(ans, Quary(t[x].ls, l, mid, L, R));
	if(R>mid) ans = min(ans, Quary(t[x].rs, mid+1, r, L, R));
	return ans;
}
void dfs(int u, int fa){
	st[u] = ++sign; v[dep[u]].push_back(u); mx = max(mx, dep[u]);
	for(int i=first[u];i;i=nxt[i]){
		int t = to[i]; if(t == fa) continue;
		dep[t] = dep[u] + 1; dfs(t, u);
	} ed[u] = sign;
}
int main(){
	n = read(), root = read();
	Build(rt[0], 1, n);
	for(int i=1; i<=n; i++) a[i] = read();
	for(int i=1; i<n; i++){
		int x = read(), y = read();
		add(x, y); add(y, x);
	} dep[root] = 1; dfs(root, 0);
	for(int i=1; i<=mx; i++){
		rt[i] = rt[i-1]; 
		for(int j=0; j<v[i].size(); j++){
			Insert(rt[i], rt[i], 1, n, st[v[i][j]], a[v[i][j]]);
		}
	}
	m = read();
	while(m--){
		int u = (read() + lastans) % n + 1, k = (read() + lastans) % n;
		lastans = Quary(rt[min(mx, dep[u] + k)], 1, n, st[u], ed[u]);
		printf("%d\n", lastans);
	} return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FSYo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值