题目链接:CodeForces 191C Fools and Roads
题目大意:
给定一个\(N\)节点的数,然后有\(M\)次操作,每次从\(u\)移动到\(v\),问说每条边被移动过的次数。
题解:
用树上差分来统计,\(u\)走向\(v\),则\(u\)、\(v\)之间的路径上的边权都加\(1\),用差分数组表示就是\(diff[u]+1, diff[v]+1, diff[lca(u,v)]-2\)。
注意以点代边的思想。
#include <iostream>
using namespace std;
struct Edge {
int v, next;
} edge[200010];
struct Line {
int x, y;
} line[100010];
int cnt, head[100010], depth[100010], fa[100010][25], diff[100010], n, m, ans[100010], id[100010];
void swap(int &x, int &y) {
x ^= y;
y ^= x;
x ^= y;
}
void addEdge(int u, int v) {
edge[++cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
void dfs(int u, int pre) {
depth[u] = depth[pre] + 1;
fa[u][0] = pre;
for (int i = 1; (1 << i) <= depth[u]; ++i) {
fa[u][i] = fa[fa[u][i - 1]][i - 1];
}
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].v;
if (v != pre) {
dfs(v, u);
}
}
}
int lca(int u, int v) {
if (depth[u] > depth[v]) {
swap(u, v);
}
for (int i = 20; i >= 0; --i) {
if (depth[u] <= depth[v] - (1 << i)) {
v = fa[v][i];
}
}
if (u == v) {
return u;
}
for (int i = 20; i >= 0; --i) {
if (fa[u][i] != fa[v][i]) {
u = fa[u][i], v = fa[v][i];
}
}
return fa[u][0];
}
void sum(int u) {
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].v;
if (v != fa[u][0]) {
sum(v);
diff[u] += diff[v];
}
}
ans[id[u]] = diff[u];
}
int main() {
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i < n; ++i) {
cin >> line[i].x >> line[i].y;
addEdge(line[i].x, line[i].y);
addEdge(line[i].y, line[i].x);
}
dfs(1, 0);
for (int i = 1; i < n; ++i) {
if (depth[line[i].x] > depth[line[i].y]) {
id[line[i].x] = i;
} else {
id[line[i].y] = i;
}
}
cin >> m;
while (m--) {
int x, y;
cin >> x >> y;
int Lca = lca(x, y);
diff[x]++;
diff[y]++;
diff[Lca] -= 2;
}
sum(1);
for (int i = 1; i < n; ++i) {
cout << ans[i] << ' ';
}
return 0;
}