P3177 [HAOI2015] 树上染色

P3177 [HAOI2015] 树上染色


题意分析

略略略~~


思路分析

我们发现将整张图直接求值似乎无法得到答案(你可以 \(O(n^2\operatorname{C}_n^k)\) 暴力骗分,但这非常不现实),那么我们可以考虑将由边组成的路径再拆回成边,统计每一条边的总贡献,然后就可以发现,一条边 \((u,v,w)\) 的贡献就是两端每种颜色的和分别相乘,再相加,最后乘上边权。

那么定义 \(f_{u,i}\) 表示在以 \(u\) 为根的子树中已经选了 \(i\) 个黑点,其中边的最大总贡献。

转移十分简单:

\[f_{u,i+j} = \max_{(u,v,w)\in G,dep_v>dep_u}{\{ f_{u,i} + f_{v,j} + \{ j (k - j) + (siz_v-j)[n-j-(siz_v-j)] \} w \}} \]

进行树形 DP,再加入上下界优化即可通过,均摊时间复杂度 \(O(nk)\)


CODE

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define max(a,b) ((a)<(b)?(b):(a))
#define min(a,b) ((a)>(b)?(b):(a))
#define tomax(a,b) ((a)=max((a),(b)))
#define tomin(a,b) ((a)=min((a),(b)))
#define RCL(a,b,c,d) memset((a),(b),sizeof(c)*(d))
#define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
#define DOR(i,a,b) for(register int i=(a);i>=(b);--i)
#define EDGE(g,i,u,x) for(register int (i)=(g).h[(u)],(x)=(g).v[(i)];(i);(i)=(g).nxt[(i)],(x)=(g).v[(i)])
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0);return Main();}signed Main
using namespace std;
constexpr int N=2e3+10;
int n,m;
int siz[N];
ll f[N][N];
struct CFS{
	int tot,h[N],v[N<<1],w[N<<1],nxt[N<<1];
	int &operator[](int i){
		return w[i];
	}
	void att(int U,int V,int W){
		v[++tot]=V,nxt[tot]=h[U],h[U]=tot,w[tot]=W;
	}
	void con(int U,int V,int W){
		att(U,V,W),att(V,U,W);
	}
}g;
void dfs(int u,int fa){
	siz[u]=1,f[u][0]=f[u][1]=0;
	EDGE(g,i,u,v)if(v^fa){
		dfs(v,u),siz[u]+=siz[v];
		DOR(j,min(m,siz[u]),0){
			if(~f[u][j])f[u][j]+=f[v][0]+(ll)siz[v]*(n-m-siz[v])*g[i];
			DOR(k,min(j,siz[v]),1)if(~f[u][j-k])
				tomax(f[u][j],f[u][j-k]+f[v][k]+(ll)(k*(m-k)+(siz[v]-k)*(n-m-siz[v]+k))*g[i]);
		}
	}
}
signed main(){
	cin>>n>>m,RCL(f,-1,f,1),tomin(m,n-m);
	FOR(i,2,n){
		int u,v,w;
		cin>>u>>v>>w,g.con(u,v,w);
	}
	dfs(1,0),cout<<f[1][m]<<endl;
	return 0;
}

posted @ 2024-07-13 16:23  Add_Catalyst  阅读(18)  评论(0)    收藏  举报