牛客多校9.E.Eyjafjalla

😊 | Powered By HeartFireY

Problem Description

题目大意:给定一棵树,以及每个点的点权,保证根节点牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_算法点权最大,离根节点越远点权越小。现在在一个节点牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_算法_02出发,选取点权位于牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_子树_03的在树上连续的点,最多可以选取多少个点。有多组询问。

首先分析题目:根据题目描述,对于任意一个非叶子节点而言,保证其子树所有点的点权全部小于其点权。那么对于感染温度范围牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_数据结构_04,感染的过程我们可以抽象成以下模型:从某个点出发,找到小于等于牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_数据结构_05的最远祖先,然后从该祖先开始向子树搜索满足大于等于牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_acm竞赛_06的节点个数。形象一点,如图所示:

牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_acm竞赛_07

牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_算法_02节点开始,向上找到满足小于等于牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_数据结构_05的祖先节点牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_算法_10,然后在牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_算法_10的子树中搜索满足大于等于牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_acm竞赛_06的节点个数。

那么分析我们解决问题的两个过程分别如何实现。

  1. 寻找对于当前节点而言最远的满足条件的祖先:这个过程很简单,我们可以在跑牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_子树_13序的过程中记录每个节点的所有祖先,然后对于每个节点遍历其全部祖先,然后找到符合要求的祖先即可。
  2. 对于子树中寻找节点数的问题,我们可以使用主席树进行维护,按牛客多校9.E.Eyjafjalla DFS序+树上倍增+主席树_子树_13​​​​​序建立主席树,然后查询子树中位于温度区间范围内的点的个数即可。

Accepted Code

#include <bits/stdc++.h>
using namespace std;

const int N = 1e3 + 10, maxn = 1e9 + 7;

int in[N], out[N], rk[N], fa[N][21], tot;
int root[N], ls[N << 5], rs[N << 5], sum[N << 5], num;
int val[N], n, m;

vector<int> g[N];

void update(int &rt, int pre, int l, int r, int x, int v){
rt = ++num, ls[rt] = ls[pre], rs[rt] = rs[pre], sum[rt] = sum[pre] + v;
if (l == r) return;
int mid = l + r >> 1;
if (x <= mid) update(ls[rt], ls[pre], l, mid, x, v);
else update(rs[rt], rs[pre], mid + 1, r, x, v);

}

int query(int rt1, int rt2, int l, int r, int L, int R){
if (l >= L && r <= R) return sum[rt2] - sum[rt1];
int ans = 0, mid = l + r >> 1;
if (L <= mid) ans += query(ls[rt1], ls[rt2], l, mid, L, R);
if (R > mid) ans += query(rs[rt1], rs[rt2], mid + 1, r, L, R);
return ans;
}

void dfs(int rt, int f){
fa[rt][0] = f, in[rt] = ++tot, rk[tot] = rt;
for (int i = 1; i <= 20; i++) fa[rt][i] = fa[fa[rt][i - 1]][i - 1];
for(auto to : g[rt]){
if(to == f) continue;
dfs(to, rt);
}
out[rt] = tot;
}

int get(int rt, int maxn){
for (int i = 20; i >= 0; i--)
if (fa[rt][i] && val[fa[rt][i]] <= maxn) rt = fa[rt][i];
return rt;
}

inline void solve(){
cin >> n;
for(int i = 1, u, v; i < n; i++){
cin >> u >> v;
g[u].push_back(v), g[v].push_back(u);
}
for(int i = 1; i <= n; i++) cin >> val[i];
dfs(1, 0);
for(int i = 1; i <= n; i++)
update(root[i], root[i - 1], 1, maxn, val[rk[i]], 1);
cin >> m;
for(int i = 1, x, L, R; i <= m; i++){
cin >> x >> L >> R;
if(val[x] >= L && val[x] <= R){
int qx = get(x, R);
cout << query(root[in[qx] - 1], root[out[qx]], 1, maxn, L, R) << endl;
}
else cout << 0 << endl;
}
}

signed main(){
freopen("stdin.in", "r", stdin);
freopen("stdout.out", "w", stdout);
ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
solve();
return 0;
}