Luogu 3899 [湖南集训]谈笑风生

时间:2023-03-09 19:21:12
Luogu 3899 [湖南集训]谈笑风生

BZOJ 3653权限题。

这题方法很多,但我会的不多……

给定了$a$,我们考虑讨论$b$的位置:

1、$b$在$a$到根的链上,那么这样子$a$的子树中的每一个结点(除了$a$之外)都是可以成为$c$的,答案就是$min(dep_a - 1, k) * (siz_a - 1)$。

2、$b$在$a$的子树中,这样子$c$的位置受$b$限制,这样子的答案就是$\sum_{x}(siz_x - 1) \ (x \in subtree(a), dep_x - dep_a \leq k)$。

第一个直接算就好,第二个可以用主席树维护出来,具体方法就和CF893F Subtree Minimum Query一样,按照深度建一棵线段树,然后查询的时候只要看一下对应深度的子树中和是多少就可以了。

所以在线的时候就可以回答了。

时间复杂度$O((n + q) logn)$。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll; const int N = 3e5 + ; int n, qn, tot = , head[N], bel[N];
int dfsc = , dep[N], siz[N], id[N]; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} struct SortNode {
int val, pos; friend bool operator < (const SortNode &x, const SortNode &y) {
return x.val < y.val;
} } so[N]; inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline int min(int x, int y) {
return x > y ? y : x;
} inline int max(int x, int y) {
return x > y ? x : y;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} void dfs(int x, int fat, int depth) {
dep[x] = depth, siz[x] = , id[x] = ++dfsc;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x, depth + );
siz[x] += siz[y];
}
} namespace SegT {
struct Node {
int lc, rc;
ll sum;
} s[N * ]; int root[N], nodeCnt = ; #define lc(p) s[p].lc
#define rc(p) s[p].rc
#define sum(p) s[p].sum
#define mid ((l + r) >> 1) void ins(int &p, int l, int r, int x, ll v, int pre) {
s[p = ++nodeCnt] = s[pre];
sum(p) += v;
if(l == r) return; if(x <= mid) ins(lc(p), l, mid, x, v, lc(pre));
else ins(rc(p), mid + , r, x, v, rc(pre));
} ll query(int p, int l, int r, int x, int y) {
if(x > y) return 0LL;
if(x <= l && y >= r) return sum(p); ll res = 0LL;
if(x <= mid) res += query(lc(p), l, mid, x, y);
if(y > mid) res += query(rc(p), mid + , r, x, y); return res;
} } using namespace SegT; int main() {
// freopen("2.in", "r", stdin);
// freopen("my.out", "w", stdout); read(n), read(qn);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
}
dfs(, , ); for(int i = ; i <= n; i++)
so[i].val = dep[i], so[i].pos = i;
sort(so + , so + + n); int maxd = ;
for(int i = ; i <= n; i++) {
ins(root[i], , n, id[so[i].pos], 1LL * (siz[so[i].pos] - ), root[i - ]);
chkMax(maxd, so[i].val);
bel[so[i].val] = i;
} for(int x, k; qn--; ) {
read(x), read(k);
ll res = 1LL * min(dep[x] - , k) * (siz[x] - );
res += query(root[bel[min(maxd, dep[x] + k)]], , n, id[x] + , id[x] + siz[x] - );
printf("%lld\n", res);
} return ;
}