一道东区dalao出的题

详情见这里 (没想到Eafoo也在qwq)

还拿了最优解QwQ

题目链接

整体思想

一个经典的思想-单独考虑每条边对答案的贡献

我们考虑一条边是否会被删除

如果这条边没有被删除

就说明这条边两侧都会有点被留下

我们不关心留下的是哪些点,只关心这条边两侧留下点的方案数

每个点有两种选择

一共就是\((2^{siz_{to}}-1)*(2^{siz_{from}}-1)\)种情况

(两边减去的1是全都不选的情况)

再乘上边权,累加起来就是答案

AC code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define int long long

using namespace std;

const int maxn=2e5+5;

const int mod=998244353;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

int n,tot,ans;
int fa[maxn];
int siz[maxn];
int head[maxn];
struct edge
{
	int from,val;
	int to,next;
}e[maxn*2];

void add(int x,int y,int w)
{
	e[++tot].to=y;
	e[tot].from=x;
	e[tot].next=head[x];
	e[tot].val=w;
	head[x]=tot;
}

int ksm(int a,int b)
{
	int ans=1;
	for(;b;b>>=1,a=(a*a)%mod)
	{
		if(b&1) ans=(ans*a)%mod;
	}
	return ans;
}

void dfs(int x,int f)
{
	siz[x]=1;fa[x]=f;
	for(int i=head[x];i;i=e[i].next)
	{
		int to=e[i].to;
		if(to==f)continue;
		dfs(to,x);
		siz[x]+=siz[to];
	}
}

signed main()
{
	n=read();
	for(int i=1;i<n;i++)
	{
		int u=read();
		int v=read();
		int w=read();
		add(u,v,w);add(v,u,w);
	}
	
	dfs(1,0);
	
	for(int i=1;i<=tot;i+=2)
	{
		int to=e[i].to;
		int u=e[i].from;
		if(fa[to]==u)
		{
			int a=ksm(2,siz[to]),b=ksm(2,n-siz[to]);
			ans=(ans+(a-1+mod)%mod*(b-1+mod)%mod*e[i].val%mod)%mod;
		}
		else
		{
			int a=ksm(2,siz[u]),b=ksm(2,n-siz[u]);
			ans=(ans+(a-1+mod)%mod*(b-1+mod)%mod*e[i].val%mod)%mod;
		}
	}
	
	cout<<ans;
	
	return 0;
}

没有样例做题确实难受qwq

UPD 在发布这篇博客5min后

现在有样例了 还是我提供的qwq

posted @ 2022-10-18 20:07  NinT_W  阅读(42)  评论(2编辑  收藏  举报