【洛谷 P3899】 [湖南集訓]談笑風生
阿新 • • 發佈:2018-10-10
class tchar == oot text oid char ++ ref ?)
題目鏈接
容易發現\(a,b,c\)肯定是在一條直鏈上的。
定義\(size(u)\)表示以\(u\)為根的子樹大小(不包括\(u\))
分兩種情況,
1、\(b\)是\(a\)的祖先,對答案的貢獻是
\[min(deep(p)-1,k)*size(p)\]
顯然是可以直接算的。
2、\(b\)是\(a\)的孩子,對答案的貢獻為
\[\sum_{\text{v是u的孩子且deep(v)<=deep(u)+k}}size[v]\]
後半段就可以主席樹來維護了。
下標為深度,值為\(\sum size\),因為同一子樹內\(dfs\)序是連續的,就像樹剖那樣用主席樹維護就好了。
(為什麽我總是不記得開\(long long\)
#include <cstdio> typedef long long ll; int s; char ch; inline int read(){ s = 0; ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s; } inline void Chkmax(int &a, int b){ if(b > a) a = b; } inline int min(int a, int b){ return a > b ? b : a; } const int MAXN = 300010; const int MAXMLOGN = 60000010; int num, maxdeep, cnt, ID, n, m, a, b; int head[MAXN], deep[MAXN], dfn[MAXN], pos[MAXN], root[MAXN], size[MAXN]; struct Tree{ ll val; int lc, rc; }t[MAXMLOGN]; inline void pushup(int now){ t[now].val = t[t[now].lc].val + t[t[now].rc].val; } int build(int l, int r){ int id = ++cnt; if(l == r) return id; int mid = (l + r) >> 1; t[id].lc = build(l, mid); t[id].rc = build(mid + 1, r); return id; } int insert(int now, int l, int r, int x, int y){ int id = ++cnt; t[id] = t[now]; if(l == r){ t[id].val += y; return id; } int mid = (l + r) >> 1; if(x <= mid) t[id].lc = insert(t[now].lc, l, mid, x, y); else t[id].rc = insert(t[now].rc, mid + 1, r, x, y); pushup(id); return id; } ll query(int p, int q, int l, int r, int wl, int wr){ if(r < wl || l > wr) return 0; if(l >= wl && r <= wr) return t[q].val - t[p].val; int mid = (l + r) >> 1; ll ans = 0; ans += query(t[p].lc, t[q].lc, l, mid, wl, wr); ans += query(t[p].rc, t[q].rc, mid + 1, r, wl, wr); return ans; } struct Edge{ int next, to; }e[MAXN << 1]; inline void Add(int from, int to){ e[++num].to = to; e[num].next = head[from]; head[from] = num; e[++num].to = from; e[num].next = head[to]; head[to] = num; } int dfs(int u, int fa){ Chkmax(maxdeep, deep[u] = deep[fa] + 1); dfn[u] = ++ID; for(int i = head[u]; i; i = e[i].next) if(e[i].to != fa) size[u] += dfs(e[i].to, u); return size[u] + 1; } int main(){ n = read(); m = read(); for(int i = 1; i < n; ++i) Add(read(), read()); dfs(1, 0); for(int i = 1; i <= n; ++i) pos[dfn[i]] = i; root[0] = build(1, maxdeep); for(int i = 1; i <= n; ++i) root[i] = insert(root[i - 1], 1, maxdeep, deep[pos[i]], size[pos[i]]); for(int i = 1; i <= m; ++i){ a = read(); b = read(); printf("%lld\n", (ll)min(deep[a] - 1, b) * size[a] + query(root[dfn[a] - 1], root[dfn[a] + size[a]], 1, maxdeep, deep[a] + 1, deep[a] + b)); } return 0; }
【洛谷 P3899】 [湖南集訓]談笑風生