6908. 【2020.11.30提高组模拟】关灯(light)/loj#3385. 「COCI 2020.11」Svjetlo

题目描述

https://loj.ac/p/3385

题解

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;
}
posted @ 2020-12-02 21:00  gmh77  阅读(187)  评论(0编辑  收藏  举报