洛谷 U140313 暗影已逝
题目背景
“光与影轮回不止”
题目描述
然而逃跑并不能阻止虫群的袭击。大主教决定吸引更多异虫来到夏古拉斯,在所有星灵撤离后,前往神庙,通过里面的机关来引爆这颗星球,以此重创异虫。
神庙记载着星灵的历史——光明圣堂武士和黑暗圣堂武士的抗争史。
机关的形状为一颗无根树。已知每个节点初始没有属性,大主教可用自己的灵能为这些节点添上一种属性(属性仅有两种,黑暗和光明,分别用0和1表示),而每一个叶子节点i都有一个触发属性Ci。Ci定义为从根节点到i上的简单路径上最后一个带有属性的节点的属性(也可以是i本身)。只有每个Ci都符合条件时,机关才可触发。
虫群已包围神庙,大主教需要在最短的时间内触发机关,于是他找到了你——JDOI滴神。他想知道最少添加几次属性能触发机关。
输入格式
第一行两个整数,N,M。分别表示节点的个数和叶子节点的个数。
第二行M个整数,表示Ci。
接下来N-1行,每行2个整数x,y。表示x到y有一条边相连。
输出格式
一个整数,表示最少操作数。
题解:
2020.11.14模拟赛T3 100分场
积累了宝贵的自己切树形DP的经验。
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e6+6;
int n,m;
int opt[maxn],cnt[2];
int tot,head[maxn],nxt[maxn<<1],to[maxn<<1];
int dp[maxn][2];
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x,int f)
{
if(x<=m)
{
if(opt[x])
dp[x][0]=1;
else
dp[x][1]=1;
return;
}
int tmp0=0,tmp1=0;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)
continue;
dfs(y,x);
tmp0+=dp[y][0];
tmp1+=dp[y][1];
}
dp[x][0]=min(tmp0,tmp1+1);
dp[x][1]=min(tmp0+1,tmp1);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d",&opt[i]);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(m+1,0);
int tmp0=0,tmp1=0;
int x=m+1;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
tmp0+=dp[y][0];
tmp1+=dp[y][1];
}
int ans=min(tmp0,tmp1);
printf("%d
",ans+1);
return 0;
}