BZOJ 3631
-
题目
-
分析
考虑 L C A LCA LCA + 差分
主要算法不讲了。。
现在考虑一下细节: a 1 → a 2 , a 2 → a 3 , . . . a n − 1 → a n a_1 \rightarrow a_2,a_2 \rightarrow a_3,...a_{n-1} \rightarrow a_{n} a1→a2,a2→a3,...an−1→an 标记点时在 a 1 → a 2 , a 2 → a 3 a_1 \rightarrow a_2,a_2 \rightarrow a_3 a1→a2,a2→a3, a 2 a_2 a2 被标记了两次,最后一个点时餐厅不用放糖果,所以这些点的最后的数目都要减一。
-
代码
const int SIZE = 300010; int f[SIZE][20], d[SIZE], dist[SIZE]; int ver[2 * SIZE], Next[2 * SIZE], edge[2 * SIZE], head[SIZE]; int T, n, m, tot, t; queue<int> q; int a[SIZE]; int cnt[SIZE]; int vis[SIZE]; void add(int x, int y, int z) { ver[++tot] = y; edge[tot] = z; Next[tot] = head[x]; head[x] = tot; } void bfs() { q.push(1); d[1] = 1; while (q.size()) { int x = q.front(); q.pop(); for (int i = head[x]; i; i = Next[i]) { int y = ver[i]; if (d[y]) continue; d[y] = d[x] + 1; dist[y] = dist[x] + edge[i]; f[y][0] = x; for (int j = 1; j <= t; j++) f[y][j] = f[f[y][j - 1]][j - 1]; q.push(y); } } } int lca(int x, int y) { if (d[x] > d[y]) swap(x, y); for (int i = t; i >= 0; i--) if (d[f[y][i]] >= d[x]) y = f[y][i]; if (x == y) return x; for (int i = t; i >= 0; i--) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i]; return f[x][0]; } void dfs(int x) { vis[x] = 1; for (int i = head[x]; i; i = Next[i]) { int y = ver[i]; if (vis[y]) continue; dfs(y); cnt[x] += cnt[y]; } } int main() { read(n); t = (int)(log(n) / log(2)) + 1; for (int i = 1; i <= n; i++) head[i] = d[i] = 0; tot = 0; for (int i = 1; i <= n; i++) read(a[i]); for (int i = 1; i < n; i++) { int x, y; read(x); read(y); add(x, y, 1), add(y, x, 1); } bfs(); for (int i = 1; i <= n - 1; i++) { int s = a[i]; int t = a[i + 1]; int _ = lca(s,t); cnt[s] ++; cnt[t] ++; cnt[_]--; cnt[f[_][0]]--; } dfs(1); for(int i = 2;i <= n;i++) cnt[a[i]]--; for(int i = 1;i <= n;i++) { out(cnt[i]); puts(""); } return 0; }
-
题型
L C A LCA LCA + 差分