这是一道模板题,区间可以用线段树来维护,也可以用树状数组来维护。
#include<bits/stdc++.h>
using namespace std;
//快读
int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c>'9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0', c = getchar();
}
return x * f;
}
const int N = 3e5 + 10;
vector<int> g[N];//存图
vector<int> p[N];//p,q
vector<pair<int, int>> q[N];//a,b,i
int ans[N];//答案
//树链剖分 重链剖分 【模板】
int fa[N], dep[N], son[N], siz[N];
void dfs1(int u, int father) {//求dep,son,siz,fa
dep[u] = dep[father] + 1, fa[u] = father,siz[u]=1;
for (auto t : g[u]) {
if (t == father) continue;
dfs1(t, u);
siz[u] += siz[t];
if (siz[son[u]] < siz[t]) {
son[u] = t;
}
}
}
int top[N], indx[N],cnt;
void dfs2(int u, int t) {//求top,indx
top[u] = t,indx[u]=++cnt;
if (!son[u]) return;
dfs2(son[u], t);
for (auto v : g[u]) {
if (v == son[u] || v == fa[u]) continue;
dfs2(v, v);
}
}
//
//线段树【模板】
#define lc u<<1
#define lr u<<1|1
struct node {
int x, y;//区间
int sum, lazy;
}tree[4*N];
void pushup(int u) {
tree[u].sum = tree[lc].sum + tree[lr].sum;
}
void pushdown(int u) {//懒标记
if (tree[u].lazy) {
tree[lc].sum += tree[u].lazy * (tree[lc].y - tree[lc].x + 1);
tree[lr].sum += tree[u].lazy * (tree[lr].y - tree[lr].x + 1);
tree[lr].lazy += tree[u].lazy;
tree[lc].lazy += tree[u].lazy;
tree[u].lazy = 0;
}
}
void build(int u, int l, int r) {
tree[u] = { l,r,0,0 };
if (l == r) return ;
int mid = l + r >> 1;
build(lc, l, mid);
build(lr, mid + 1, r);
pushup(u);
}
//查询
int query(int u,int l,int r) {
if (tree[u].x >= l && tree[u].y <= r) return tree[u].sum;
pushdown(u);
int mid = tree[u].x + tree[u].y >> 1;
int res = 0;
if(l<=mid) res=query(lc, l, r);
if (r > mid) res += query(lr, l, r);
return res;
}
//【模板】 求树上最小权重和
// 此题没有用到
int query_path(int u, int v) {
int res = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(v, u);
res += query(1,indx[top[u]],indx[u]);
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(v, u);
res += query(1, indx[v], indx[u]);
return res;
}
//修改
void updata(int u, int l, int r, int k) {
if (tree[u].x >= l && tree[u].y <= r) {
tree[u].sum += k * (tree[u].y - tree[u].x + 1);
tree[u].lazy += k;//懒标记
return;
}
pushdown(u);
int mid = tree[u].x + tree[u].y >> 1;
if (l <= mid) updata(lc, l, r, k);
if (r > mid) updata(lr, l, r, k);
pushup(u);
}
void dfs3(int u, int father) {//求ans
for (auto v : p[u]) {
updata(1, indx[v], indx[v], 1);//记录q点的位置+1
}
for (auto t : q[u]) {//遍历在p子孙里的a的b
int v = t.first, id = t.second;
ans[id] = query(1, indx[v], indx[v] + siz[v] - 1);//如果q在b的子树里就加上
}
for (auto v : g[u]) {//继续遍历下一个节点
if (v == father) continue;
dfs3(v, u);
}
for (auto v : p[u]) {//子树遍历完后及时删除,因为要保证p是a的祖先
updata(1, indx[v], indx[v] ,-1);
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
int n, m, k;
//cin >> n >> m >> k;
n = read(), m = read(), k = read();
for (int i = 1; i < n; i++) {
int x, y;
//cin >> x >> y;
x = read(), y = read();
g[x].push_back(y);
g[y].push_back(x);
}
dfs1(1, 0);
dfs2(1,1);
build(1, 1, n);
for (int i = 1; i <= m; i++) {
int x, y;
//cin >> x >> y;
x = read(), y = read();
p[x].push_back(y);
}
for (int i = 1; i <= k; i++) {
int a, b;
//cin >> a >> b;
a = read(), b = read();
q[a].push_back({ b,i });//类似taryan算法的求值,i是第几个问题
}
dfs3(1, 0);
for (int i = 1; i <= k; i++) cout << ans[i] << '\n';
return 0;
}