Codeforces 191C Fools and Roads

問題

無向木が与えられる。
この木上を、m個の出発点とゴールの組(ui, vi)について、
uiから一人が出発し、viへゴールする。


それぞれの辺について、合計何人が通るか求めよ。

制約条件

n≦10^5
m≦10^5

方針

累積和するだけ。
まずは木の根をどれか定める。


そしたら、num[u[i]], num[v[i]]に1を足して、
u, vのlcaのnumから2を引く。
それで累積和を、木の葉のほうから根のほうに向かって求めればいい。
これは再帰で出来る。

ソースコード

const int MX = 100010;
const int MX_L=17;

int n, ans[MX], num[MX];
int parent[MX_L][MX];
int depth[MX];
vector<vi> e, id;

void dfs(int c, int p, int d){
	depth[c] = d;
	parent[0][c] = p;
	rep(i, e[c].size()){
		int to = e[c][i];
		if(to == p) continue;
		dfs(to, c, d + 1);
	}
}
inline int lca(int a, int b){
	if(depth[a] > depth[b]) swap(a, b);
	int d = depth[b] - depth[a];
	rep(i, MX_L) if(d & 1 << i) b = parent[i][b];
	if(a == b) return a;
	for(int i = MX_L - 1; i >= 0; i--) if(parent[i][a] != parent[i][b]){
		a = parent[i][a];
		b = parent[i][b];
	}
	return parent[0][a];
}

void rec(int c, int p){
	rep(i, e[c].size()) if(e[c][i] != p){
		rec(e[c][i], c);
		ans[id[c][i]] += num[e[c][i]];
		num[c] += num[e[c][i]];
	}
}

int main()
{
	cin >> n;
	e.resize(n);
	id.resize(n);
	rep(i, n - 1){
		int a, b;
		cin >> a >> b;
		a--; b--;
		e[a].pb(b); e[b].pb(a);
		id[a].pb(i); id[b].pb(i);
	}
	
	//n for dummy root
	parent[0][n] = n;
	dfs(0, n, 1);
	rep(i, MX_L - 1) rep(j, n) parent[i + 1][j] = parent[i][parent[i][j]];
	
	int m;
	cin >> m;
	while(m--){
		int a, b;
		cin >> a >> b;
		a--; b--;
		int u = lca(a, b);
		num[a]++; num[b]++; num[u] -= 2;
	}
	rec(0, 0);
	assert(num[0] == 0);
	
	rep(i, n - 1) cout << ans[i] << " ";
	cout << endl;
	
	return 0;
}