翻书就好了,在树上差分的第一个例题,书上讲得太好了感觉我写啥都是多余。Cat本来可以1A的,结果把m看成了树边和非树边总共有m条,算贡献的时候算成了n-m...过样例的的时候读入错了我就发现了这个问题,结果改了一处没改第二处……
有大佬说能用树链剖分+线段树,我懒了就没试,我的树链剖分是用来找lca的。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 2; const ll mod = 1e9 + 7; int n, m, top[maxn], fa[maxn], siz[maxn], dfn[maxn], rnk[maxn]; int c[maxn], dep[maxn], son[maxn], ntime; ll ans; struct node { int next, to; }a[maxn<<1]; int head[maxn], len; void add(int x, int y) { a[++len].to = y; a[len].next = head[x]; head[x] = len; } void find_heavy_edge(int u, int fat, int depth) { fa[u] = fat; dep[u] = depth; siz[u] = 1; son[u] = 0; int maxsize = 0; for(int i=head[u]; i; i=a[i].next) { int v = a[i].to; if(dep[v]) continue; find_heavy_edge(v, u, depth+1); siz[u] += siz[v]; if(siz[v] > maxsize) { maxsize = siz[v]; son[u] = v; } } } void connect_heavy_edge(int u, int ancestor) { dfn[u] = ++ntime; top[u] = ancestor; rnk[ntime] = u; if(son[u]) { connect_heavy_edge(son[u], ancestor); } for(int i=head[u]; i; i=a[i].next) { int v = a[i].to; if(v == son[u] || v == fa[u]) continue; connect_heavy_edge(v, v); } } int LCA(int x, int y) { while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x, y); x = fa[top[x]]; } if(dep[x] > dep[y]) swap(x, y); return x; } void dfs(int u) { for(int i=head[u]; i; i=a[i].next) { int v = a[i].to; if(v == fa[u]) continue; dfs(v); c[u] += c[v]; } if(u != 1) { if(c[u] == 0) ans += m; else if(c[u] == 1) ans++; } } int main() { scanf("%d%d", &n, &m); for(int i=1; i<n; i++) { int x, y; scanf("%d%d", &x, &y); add(x, y); add(y, x); } find_heavy_edge(1, 1, 1); connect_heavy_edge(1, 1); for(int i=1; i<=m; i++) { int x, y; scanf("%d%d", &x, &y); c[x]++; c[y]++; int lca = LCA(x, y); c[lca] -= 2; } dfs(1); printf("%lld\n", ans); return 0; }View Code
(如果你算错了,就会被liu_runda拿去喂兔子,啊呜~~)
我不会算,兔子你吃了我吧,撑不死你……