6908. 【2020.11.30提高组模拟】关灯(light)/loj#3385. 「COCI 2020.11」Svjetlo
作者:互联网
题目描述
题解
dp维护路径线条,每次把当前的线条拆开加上新的
设f[i,0/1,0/1/2]表示点i颜色为0/1,下面已固定了0/1/2个端点的答案
分类讨论,注意可以多折一次来改变i和儿子的颜色,走完的儿子颜色必须为1
一开始拓扑求出0的虚树,在上面dp即可
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define pd(x,y) (bg[x]<=bg[y] && ed[y]<=ed[x])
#define min(a,b) (a<b?a:b)
#define Min(a,b) a=min((a),(b))
#define max(a,b) (a>b?a:b)
#define ll long long
#define file
using namespace std;
int b[500001],n,i,j,k,l,rt;
int a[1000001][2],ls[500001],len;
int f[500001][2][3];
bool bz[500001];
char st[500001];
void init()
{
static int d[500001],D[500001];
int h=0,t=0,i,j,k,l;
memset(D,0,sizeof(D));
fo(i,1,n) for (j=ls[i]; j; j=a[j][1]) ++D[a[j][0]];
fo(i,1,n) if (b[i] && D[i]<=1) d[++t]=i;
while (h<t)
{
++h,bz[d[h]]=1;
for (i=ls[d[h]]; i; i=a[i][1])
{
--D[a[i][0]];
if (D[a[i][0]]==1 && b[a[i][0]]) d[++t]=a[i][0];
}
}
}
void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
void dfs(int Fa,int t)
{
int i,j,k,l,x;
int F[2][3];
f[t][b[t]^1][0]=1;
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa && !bz[a[i][0]])
{
dfs(t,a[i][0]);x=a[i][0];
if (!bz[x])
{
memset(F,1,sizeof(F));
fo(j,0,1)
{
Min(F[j^1][0],f[t][j][0]+f[x][1][0]+1);
Min(F[j][0],f[t][j][0]+f[x][0][0]+3);
Min(F[j][1],f[t][j][0]+f[x][1][1]);
Min(F[j^1][1],f[t][j][0]+f[x][0][1]+2);
Min(F[j][2],f[t][j][0]+f[x][0][2]+1);
Min(F[j^1][2],f[t][j][0]+f[x][1][2]+3);
Min(F[j^1][1],f[t][j][1]+f[x][1][0]+1);
Min(F[j][1],f[t][j][1]+f[x][0][0]+3);
Min(F[j][2],f[t][j][1]+f[x][1][1]);
Min(F[j^1][2],f[t][j][1]+f[x][0][1]+2);
Min(F[j^1][2],f[t][j][2]+f[x][1][0]+1);
Min(F[j][2],f[t][j][2]+f[x][0][0]+3);
}
memcpy(f[t],F,sizeof(F));
}
}
fo(i,0,1) fo(j,1,2) f[t][i][j]=min(f[t][i][j],f[t][i][j-1]);
}
int main()
{
#ifdef file
// freopen("loj3385.in","r",stdin);
freopen("light.in","r",stdin);
freopen("light.out","w",stdout);
#endif
scanf("%d",&n);
scanf("%s",st+1);
fo(i,1,n) b[i]=st[i]=='1';
fo(i,1,n-1) scanf("%d%d",&j,&k),New(j,k),New(k,j);
memset(f,1,sizeof(f));
init();
fo(i,1,n) if (!bz[i]) break;rt=i;
dfs(0,rt);
printf("%d\n",f[rt][1][2]);
fclose(stdin);
fclose(stdout);
return 0;
}
标签:3385,loj,int,ls,2020.11,500001,fo,define 来源: https://www.cnblogs.com/gmh77/p/14076436.html