中文题题意不解释~
还是比较基础的树形dp~
思路: 每个父亲节点还是由子节点推过来的,所以只需要统计子节点的状态就可以了,用dpa[i][j]来表示涂绿,蓝和啥的时候最多有几个节点是绿色的,dpi则是表示最少有几个节点是绿色的。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 5e5 + 50;
const int inf = 0x3f3f3f3f;
char str[maxn];
int numa[maxn];
int a[maxn][2];
int thi = 0;
int dpa[maxn][3],dpi[maxn][3];
void build(int num,int root)
{
numa[root] = num;
if(num >= 1)
{
++thi;
a[root][0] = thi;
build(str[thi]-'0', thi);
}
if(num >= 2)
{
++thi;
a[root][1] = thi;
build(str[thi] -'0',thi);
}
}
void solve(int u)
{
if(numa[u] == 0)
{
dpa[u][0] = 1, dpa[u][1] = 0, dpa[u][2] = 0;
dpi[u][0] = 1, dpi[u][1] = 0, dpi[u][2] = 0;
return;
}
if(numa[u] == 1)
{
int v = a[u][0];
solve(v);
dpa[u][0] = max(dpa[v][1], dpa[v][2]) + 1;
dpa[u][1] = max(dpa[v][0], dpa[v][2]);
dpa[u][2] = max(dpa[v][1], dpa[v][0]);
dpi[u][0] = min(dpi[v][1], dpi[v][2]) + 1;
dpi[u][1] = min(dpi[v][0], dpi[v][2]);
dpi[u][2] = min(dpi[v][1], dpi[v][0]);
}
else if(numa[u] == 2)
{
int v1 = a[u][0], v2 = a[u][1];
solve(v1); solve(v2);
dpa[u][0] = max(dpa[v1][1] + dpa[v2][2], dpa[v1][2] + dpa[v2][1]) + 1;
dpa[u][1] = max(dpa[v1][0] + dpa[v2][2], dpa[v1][2] + dpa[v2][0]);
dpa[u][2] = max(dpa[v1][1] + dpa[v2][0], dpa[v1][0] + dpa[v2][1]);
dpi[u][0] = min(dpi[v1][1] + dpi[v2][2], dpi[v1][2] + dpi[v2][1]) + 1;
dpi[u][1] = min(dpi[v1][0] + dpi[v2][2], dpi[v1][2] + dpi[v2][0]);
dpi[u][2] = min(dpi[v1][1] + dpi[v2][0], dpi[v1][0] + dpi[v2][1]);
}
}
int main()
{
scanf("%s",str);
memset(a,-1,sizeof(a));
build(str[0]-'0',0);
solve(0);
int maxi = 0, mini = inf;
for(int i = 0; i < 3;i ++)
{
maxi = max(dpa[0][i], maxi);
mini = min(dpi[0][i], mini);
}
printf("%d %d\n",maxi , mini);
return 0;
}