首页 > 其他分享 >CF955F Heaps

CF955F Heaps

时间:2022-10-02 21:24:50浏览次数:58  
标签:Heaps fa int CF955F dep tt dp deg

\(\tt CF955F\),\(\tt^\ast2600\)。

首先要知道:设 \(deg_u\) 为 \(u\) 的儿子个数,有 \(\sum deg_u=O(n)\)。

我们考虑求出 \(dp_k(u)\),然后一个一个加。

但是这个不太好直接求,所以可以求出一个弱化一点的东西:\(f_k(u)\) 代表 \(u\) 子树内 以 \(u\) 为根 的 \(k\) 叉树最大深度。

容易发现 \(f_k(u)\) 分成两类,一类 \(\gt1\),一类 \(=1\)。容易发现后者居多,而前者只有 \(\sum deg_u=O(n)\) 种。

我们希望让复杂度尽量优秀,于是考虑 \(O(n)\) 的时间里求出 \(f_{k}(u)\) 的所有非 \(1\) 状态。

我们考虑树形 \(\tt DP\) 来求这个东西,设 \(S_{u,k}=\{f_{v,k}\}\),其中 \(v\) 是 \(u\) 的儿子,那么有 \(f_{u,k}=\mathtt{kth}(S_{u,k},k)+1\),其中 \(\tt kth\) 是取 \(k\) 大的意思。

原因很显然,如果第 \(k\) 大为 \(x\),说明至少有 \(k\) 个 \(v\) 使得 \(f_{v,k}\ge x\),那么以这 \(k\) 个儿子各自建 \(k\) 叉树,\(u\) 连向着 \(k\) 个儿子,新 \(k\) 叉树深度一定 \(\ge x+1\)。

\(\tt kth\) 就是 \(\texttt{std::nth\_element}\)。

那我们怎么通过这个 \(f\) 推到复杂的 \(dp\) 呢?其实 \(dp\) 就是 \(f\) 的子树最大值。但是 \(dp\) 不能直接暴力累加,因为它的状态数不是 \(O(n)\) 的。

我们分开每个 \(k=1,\cdots,n\) 来处理 \(\sum dp_k(u)\),对于某个 \(k\),我们把 \(deg_u\le k\) 的 \(u\) 建成一棵虚树(复杂度 \(\sum deg_u\))。

我们考虑虚树上一条边 \(fa\to u\),并且 \(dp_k(u)=x\)。这时候对于 \(p\in\{fa,\cdots,u\}\) 这条链除去 \(fa\),\(dp_k(p)=x\)。所以 \(u\) 的贡献是 (dep[u]-dep[fa])*dp[u][k]

那就是一个简单的虚树 \(\tt DP\) 了。

求 \(f\) 和虚树 \(\tt DP\) 都可以很简单的做到线性。(我的实现)做不到线性的原因是我不想写 \(O(n)-O(1)\) 的 \(\tt LCA\)(建虚树),最后就是 \(O(n\log n)\)。

#include<bits/stdc++.h>
using namespace std;

const int N = 3e5 + 5;

int n,dep[N],dfn[N],deg[N],tot;
vector<int> G[N],T[N],dp[N],tmp[N],P,Q;
long long cnt;
int d,ft[20][N],stk[N];

void dfs(int u,int fa){
	dep[u] = dep[ft[0][u] = fa] + 1; dfn[u] = ++tot;
	dp[u].resize(1 + (deg[u] = G[u].size() - (u != 1)));
	if(deg[u]) P.push_back(u);
	for(int i = 1;i < 20;++i) ft[i][u] = ft[i - 1][ft[i - 1][u]];
	for(int v : G[u]) if(v != fa) dfs(v,u);
	for(int v : G[u]) if(v != fa)
		for(int j = 1;j <= min(deg[u],deg[v]);++j) tmp[j].push_back(dp[v][j]);
	for(int i = 1;i <= deg[u];++i){
		if(tmp[i].size() < i){ dp[u][i] = 2; tmp[i].clear(); continue; }
		auto p = begin(tmp[i]) + (i - 1);
		nth_element(begin(tmp[i]),p,end(tmp[i]),greater<int>());
		dp[u][i] = *p + 1; tmp[i].clear();
	}
}

int lca(int u,int v){
	if(dep[u] < dep[v]) swap(u,v);
	for(int i = 19;~i;--i) if(dep[v] <= dep[u] - (1 << i)) u = ft[i][u];
	if(u == v) return u;
	for(int i = 19;~i;--i) if(ft[i][u] != ft[i][v]) u = ft[i][u],v = ft[i][v];
	return ft[0][u];
}

int ans(int u,int ft){
	int R = deg[u] < d ? 1 : dp[u][d];
	for(int v : T[u]) R = max(R,ans(v,u));
	T[u].clear();
	return cnt += 1LL * (dep[u] - dep[ft]) * (R - 1),R;
}

int main(){
	scanf("%d",&n);
	for(int i = 1,u,v;i < n;++i){
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1,0);
	for(d = 1;d <= n;++d){
		int tp = 0;
		for(int x : P){
			if(!tp){ stk[++tp] = x; continue; }
			int z = lca(stk[tp],x);
			while(dep[z] < dep[stk[tp - 1]])
				T[stk[tp - 1]].push_back(stk[tp]),--tp;
			if(z != stk[tp]){
				T[z].push_back(stk[tp]);
				stk[tp - 1] == z ? --tp : stk[tp] = z;
			}
			stk[++tp] = x;
		}
		while(--tp) T[stk[tp]].push_back(stk[tp + 1]);
		ans(1,0); swap(P,Q); P.clear();
		for(int x : Q) if(deg[x] != d || x == 1) P.push_back(x);
	}
	printf("%lld\n",cnt + (1LL * n * n));
	return 0;
}

标签:Heaps,fa,int,CF955F,dep,tt,dp,deg
From: https://www.cnblogs.com/zeno6174/p/CF955F.html

相关文章