一道东区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