题目链接:https://ac.nowcoder.com/acm/contest/11260/E
分析
先跑一边dfs处理出每个点的dfs序就能得到以每个点为根节点的子树所拥有的点的dfs序的区间,如图
由于是dfs序,每个点的子树所包含的所有点的dfs序是连续的。
我们先根据每个查询的
l
l
l和
r
r
r,向上找到距离开始点最远的在区间内的点,答案就是以该点为根的子树大小减去该点的dfs序区间内温度小于等于
x
−
1
x-1
x−1的点的数量。
由于查询次数较多,我们可以记录每次要查询的dfs序区间以及
x
−
1
x-1
x−1,用树状数组离线查找。
代码
树状数组做法
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 100000 + 10;
int n, q, c[maxn], ans[maxn];
int deep[maxn],pre[maxn][64];
vector<int> g[maxn];
int cnt = -1, rr[maxn], tp[maxn], s[maxn], dfn[maxn];
struct x {
int d;
int p;
bool operator <(x c)const {
return d < c.d;
};
} a[maxn];
struct query {
int l, r, x;
int id;
bool operator <(query c) const {
return x < c.x;
}
} Q[maxn];
void add(int x) {
while(x <= n) {
c[x]++;
x += (x & (-x));
}
}
int sum(int x) {
int s = 0;
while(x > 0) {
s += c[x];
x -= (x & (-x));
}
return s;
}
void dfs(int u, int fa)
{
deep[u]=deep[fa]+1;
pre[u][0]=fa;
for(int i=1;(1<<i)<=deep[u];i++)
pre[u][i]=pre[pre[u][i-1]][i-1];
s[u] = 1;
a[u].p = ++cnt;
dfn[u] = cnt;
for(int i=0;i<g[u].size();i++)
{
if(g[u][i] == fa) continue;
dfs(g[u][i], u);
s[u] += s[g[u][i]];
}
rr[u] = cnt;
}
int main() {
scanf("%d", &n);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=n;i++) scanf("%d",&tp[i]), a[i].d = tp[i];
dfs(1, 0);
sort(a + 1, a + 1 + n);
scanf("%d",&q);
for(int i = 0; i < q; i++) {
Q[i].id = i;
int u,L,R;
scanf("%d%d%d", &u, &L, &R);
if(tp[u] < L || tp[u] > R)
{
Q[i].x = -1;
ans[i] = 0;
continue;
}
int l=0,r=deep[u]-deep[1];
int v = u;
while(l<r)
{
int du=u;
int mid=(l+r+1)/2;
for(int i=30;i>=0;i--) if((mid>>i)&1) du=pre[du][i];
if(tp[du]>R) r=mid-1;
else
{
l=mid;
v = du;
}
}
Q[i].l = dfn[v];
Q[i].r = rr[v];
ans[i] = s[v];
Q[i].x = L - 1;
}
sort(Q, Q + q);
int l = 1;
for(int i = 0; i < q; i++) {
if(Q[i].x == -1) continue;
x tmp;
tmp.p = 1;
tmp.d = Q[i].x;
int pos = upper_bound(a + 1, a + 1 + n, tmp) - a;
while(l < pos) {
add(a[l].p);
l++;
}
ans[Q[i].id] -= sum(Q[i].r) - sum(Q[i].l - 1);
}
for(int i = 0; i < q; i++)
printf("%d\n", ans[i]);
return 0;
}
主席树做法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 10;
int n, q, m;
int deep[maxn],pre[maxn][64];
vector<int> g[maxn];
int cnt, rr[maxn], tp[maxn], dfn[maxn];
int t[maxn * 20], sum[maxn * 20], L[maxn * 20], R[maxn * 20], idx, a[maxn], b[maxn];
void build(int &rt, int l, int r)
{
rt = ++idx;
sum[rt] = 0;
if(l == r) return;
int mid = (l + r) >> 1;
build(L[rt], l, mid);
build(R[rt], mid + 1, r);
}
void update(int &rt, int pre, int l, int r, int pos)
{
rt = ++idx;
L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre] + 1;
if(l == r) return;
int mid = (l + r) >> 1;
if(pos <= mid) update(L[rt], L[pre], l, mid, pos);
if(pos > mid) update(R[rt], R[pre], mid + 1, r, pos);
}
int query(int tl, int tr, int l, int r, int pos)
{
if(l == r) return sum[tr] - sum[tl];
int mid = (l + r) >> 1;
int res = 0;
if(pos <= mid)
{
res += sum[R[tr]] - sum[R[tl]];
res += query(L[tl], L[tr], l, mid, pos);
}
else res += query(R[tl], R[tr], mid + 1, r, pos);
return res;
}
void dfs(int u, int fa)
{
deep[u]=deep[fa]+1;
pre[u][0]=fa;
for(int i=1;(1<<i)<=deep[u];i++)
pre[u][i]=pre[pre[u][i-1]][i-1];
dfn[u] = ++cnt;
a[cnt] = tp[u];
for(int i=0;i<g[u].size();i++)
{
if(g[u][i] == fa) continue;
dfs(g[u][i], u);
}
rr[u] = cnt;
}
int main() {
scanf("%d", &n);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=n;i++) scanf("%d",&tp[i]), b[i] = tp[i];
dfs(1, 0);
sort(b + 1, b + 1 + n);
m = unique(b + 1, b + 1 + n) - b - 1;
build(t[0], 1, m);
for(int i=1;i<=cnt;i++)
{
int pos = lower_bound(b + 1, b + 1 + m, a[i]) - b;
update(t[i], t[i - 1], 1, m, pos);
}
scanf("%d",&q);
for(int i = 0; i < q; i++) {
int u,ql,qr;
scanf("%d%d%d", &u, &ql, &qr);
if(tp[u] < ql || tp[u] > qr)
{
printf("0\n");
continue;
}
int l=0,r=deep[u]-deep[1];
int v = u;
while(l<r)
{
int du=u;
int mid=(l+r+1)/2;
for(int i=30;i>=0;i--) if((mid>>i)&1) du=pre[du][i];
if(tp[du]>qr) r=mid-1;
else
{
l=mid;
v = du;
}
}
int tt = lower_bound(b + 1, b + 1 + m, ql) - b;
printf("%d\n",query(t[dfn[v] - 1], t[rr[v]], 1, m, tt));
}
return 0;
}