bzoj4390
树上差分
感觉挺巧妙的。。。
每次更新就是在u,v上+1,x是lca(u,v),在x和fa[x]上-1,那么每个点的权值就是子树和,正确性yy一下就行了
不过树状数组的常数真是小,改成前缀和才快了200ms
#include<bits/stdc++.h> using namespace std; const int N = 100010; int n, m, ans, cnt = 1, dfs_clock; int head[N], fa[N][23], in[N], out[N], dep[N], sum[N]; struct edge { int nxt, to; } e[N << 1]; void link(int u, int v) { e[++cnt].nxt = head[u]; head[u] = cnt; e[cnt].to = v; } int lca(int u, int v) { if(dep[u] < dep[v]) swap(u, v); int d = dep[u] - dep[v]; for(int i = 22; i >= 0; --i) if(d & (1 << i)) u = fa[u][i]; if(u == v) return u; for(int i = 22; i >= 0; --i) if(fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } return fa[u][0]; } void dfs(int u, int last) { in[u] = ++dfs_clock; for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != last) { fa[e[i].to][0] = u; dep[e[i].to] = dep[u] + 1; dfs(e[i].to, u); } out[u] = dfs_clock; } int main() { scanf("%d%d", &n, &m); for(int i = 1; i < n; ++i) { int u, v; scanf("%d%d", &u, &v); link(u, v); link(v, u); } dfs(1, 0); for(int j = 1; j <= 22; ++j) for(int i = 1; i <= n; ++i) fa[i][j] = fa[fa[i][j - 1]][j - 1]; while(m--) { int u, v, x; scanf("%d%d", &u, &v); x = lca(u, v); ++sum[in[u]]; ++sum[in[v]]; --sum[in[x]]; --sum[in[fa[x][0]]]; } for(int i = 1; i <= n; ++i) sum[i] += sum[i - 1]; for(int i = 1; i <= n; ++i) ans = max(ans, sum[out[i]] - sum[in[i] - 1]); printf("%d\n", ans); return 0; }