“This is a big mistake!”
主席树的迁移
如何把对主席树“能解决区间第 k 大问题”这个印象迁移到这道非常暴力的题目上呢?我们可以把整棵树用 DFS 序来入手(连续性在本题会比离散型更好)。我们可以先用一个 DFS 来记录 DFS 序、Low 数组、子树大小。
然后,我们以深度为权值,子树大小为要维护的信息。以 DFS 序的顺序来计算前缀子树和、创建主席树。具体见代码:
代码
// P3899.cpp
#include <iostream>
#include <cstdio>
#include <vector>
#define ll long long
#define mid ((l + r) >> 1)
using namespace std;
const ll MX_N = 3e5 + 1000;
ll ncnt, dfn[MX_N], low[MX_N], antiDFN[MX_N], ndfn, dep[MX_N], fa[MX_N], n, q, tmpx, tmpy;
ll subtree[MX_N], roots[MX_N];
vector<ll> G[MX_N];
struct node
{
ll sum, ls, rs;
} nodes[MX_N * (2 << 5)];
ll build(ll l, ll r)
{
ll p = ++ncnt;
if (l == r)
return p;
nodes[p].ls = build(l, mid), nodes[p].rs = build(mid + 1, r);
nodes[p].sum = 0;
return p;
}
ll update(ll l, ll r, ll previous, ll depth, ll ad)
{
ll curt = ++ncnt;
nodes[curt].ls = nodes[previous].ls, nodes[curt].rs = nodes[previous].rs;
nodes[curt].sum = nodes[previous].sum + ad;
if (l == r && l == depth)
return curt;
if (depth <= mid)
nodes[curt].ls = update(l, mid, nodes[previous].ls, depth, ad);
else
nodes[curt].rs = update(mid + 1, r, nodes[previous].rs, depth, ad);
return curt;
}
ll query(ll ql, ll qr, ll l, ll r, ll p)
{
if (ql <= l && r <= qr)
return nodes[p].sum;
if (mid >= qr)
return query(ql, qr, l, mid, nodes[p].ls);
if (mid < ql)
return query(ql, qr, mid + 1, r, nodes[p].rs);
return query(ql, qr, l, mid, nodes[p].ls) + query(ql, qr, mid + 1, r, nodes[p].rs);
}
void dfs(ll u)
{
dfn[u] = ++ndfn, subtree[u]++;
antiDFN[ndfn] = u, dep[u] = dep[fa[u]] + 1;
ll siz = G[u].size();
for (ll i = 0; i < siz; i++)
if (G[u][i] != fa[u])
fa[G[u][i]] = u, dfs(G[u][i]), subtree[u] += subtree[G[u][i]];
low[u] = ndfn;
}
int main()
{
scanf("%lld%lld", &n, &q);
for (int i = 0; i < n - 1; i++)
scanf("%lld%lld", &tmpx, &tmpy), G[tmpx].push_back(tmpy), G[tmpy].push_back(tmpx);
dfs(1), roots[0] = build(1, n);
for (int i = 1; i <= n; i++)
roots[i] = update(1, n, roots[i - 1], dep[antiDFN[i]], subtree[antiDFN[i]] - 1);
while (q--)
{
scanf("%lld%lld", &tmpx, &tmpy);
ll ret = min(dep[tmpx] - 1, tmpy) * (subtree[tmpx] - 1);
ll another = query(dep[tmpx], dep[tmpx] + tmpy, 1, n, roots[low[tmpx]]) -
query(dep[tmpx], dep[tmpx] + tmpy, 1, n, roots[dfn[tmpx]]);
printf("%lld\n", ret + another);
}
return 0;
}