题解 CF1401D 【Maximum Distributed Tree】

题解 - C F 1401 D \mathrm{CF1401D} CF1401D

题目意思

题目传送门

S o l \mathrm{Sol} Sol

简单树上贪心

我们肯定考虑一条边的权值 v i v_i vi 左边有 l s ls ls 个点右边就 ( n − l s ) (n-ls) (nls) 个点,那么这条边的贡献为 l s ( n − l s ) × v i ls(n-ls)\times v_i ls(nls)×vi

那么我们肯定尽量让大的权值的贡献最大,从大到小排个序累加一下即可,剩下的就是简单模拟一下。

时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)

C o d e \mathrm{Code} Code

const int N=2e5+5;

int n,m,siz[N],head[N],cnt,P[N],S[N],bo[N],cwy,ans;

struct Node
{
	int nex,to;
};
Node e[N<<1];

inline void jia(int u,int v)
{
	e[++cnt].nex=head[u];
	head[u]=cnt;
	e[cnt].to=v;
}

inline void dfs(int u,int fa)
{
	siz[u]=1;
	GO(i,u)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
		S[++cwy]=siz[v]*(n-siz[v]);//记录每条边的贡献
	}
}

inline bool Cmp(int x,int y) { return x>y; }
inline void Add(int &x,int y) { x+=y; if(x>=mod) x-=mod; }

signed main()
{
	int Q;
	io.read(Q);
	for (;Q--;)
	{
		io.read(n);
		For(i,1,n) head[i]=0,siz[i]=0;
		cwy=cnt=ans=0;
		For(i,1,n-1)
		{
			int x,y;
			io.read(x),io.read(y);
			jia(x,y);
			jia(y,x);
		}
		io.read(m);
		For(i,1,m) io.read(P[i]);
		dfs(1,0);
		sort(P+1,P+m+1,Cmp);
		sort(S+1,S+cwy+1,Cmp);//分别从大到小排序
		if(m<n)
		{
			For(i,m+1,n) P[i]=1;//不足n-1条边就用1补齐
			For(i,1,n-1) Add(ans,P[i]*S[i]%mod);
			io.write((ans+mod)%mod);
			puts("");
		}
		else 
		{
			int st=m-n+2;
			int tot=1ll;
			For(i,1,st) tot=tot*P[i]%mod;
			ans=tot*S[1]%mod;
            //否则把前面几个大的合并记录贡献
			For(i,2,n-1) Add(ans,P[st+i-1]*S[i]%mod);
			io.write((ans+mod)%mod);
			puts("");
		}
	}
	return 0;
}
	
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值