kmjp's blog

競技プログラミング参加記です

yukicoder : No.1098 LCAs

ここら辺はまだ簡単。
https://yukicoder.me/problems/no/1098

問題

根付き木が与えられる。
f(k)を、頂点対(u,v)のうちLCAが頂点kになるものの数とする。
各kに対しf(k)を求めよ。

解法

頂点kの各子頂点のSubtreeの頂点数からなる配列をCとする。
2つの異なる子頂点のSubTreeから2点選ぶ、もしくは1個以上の頂点をkとすると、LCAがkになる。
よって
 \displaystyle f(x) = 1 + \sum_{0 \le i \lt |C|} C_i +2\times\sum_{0 \le i \lt j \lt |C|} C_i \times C_j
となる。

int N;
vector<int> E[202020];
int C[202020];
ll ret[202020];

int dfs(int cur,int pre) {
	C[cur]=1;
	ret[cur]=1;
	FORR(e,E[cur]) if(e!=pre) {
		int add=dfs(e,cur);
		ret[cur]+=2LL*C[cur]*add;
		C[cur]+=add;
	}
	return C[cur];
}


void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N;
	FOR(i,N-1) {
		cin>>x>>y;
		E[x].push_back(y);
		E[y].push_back(x);
	}
	dfs(1,1);
	FOR(i,N) cout<<ret[i+1]<<endl;
}

まとめ

これは★2.5でもいいかもね。