P2585 [ZJOI2006]三色二叉树 解题报告
考察:树形dp
思路:
树上最大值,最小值,方案数是树形dp常考的问题.这里设置f[i][j]为在以i为根的子树中,i的颜色是j的最大结点数.
设置2为绿色,初始化所有f[i][2] = 1.如果当前父节点u只有一个子结点x f[u][k] += max(f[x][j]) j!=k.
如果有两个子结点,就需要三个结点的颜色互不相同. 此时可以先计算完两个子结点再计算父节点,而非常规树形dp枚举一个子结点就更新父节点
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 using namespace std; 6 typedef long long LL; 7 const int N = 500010,M = 1e6+10; 8 char s[N]; 9 int idx = 1,len,p=1; 10 vector<int> v[M]; 11 LL f[M][3][2]; 12 void build(int st) 13 { 14 if(p>len) return; 15 int sz = s[p]-'0'; 16 p++; 17 while(sz--) 18 v[st].push_back(++idx); 19 for(int i=0;i<v[st].size();i++) 20 build(v[st][i]); 21 } 22 void dfs(int u) 23 { 24 f[u][2][0] = f[u][2][1] = 1; 25 for(int i=0;i<v[u].size();i++) 26 { 27 int t = v[u][i]; 28 dfs(t); 29 } 30 if(v[u].size()==1) 31 { 32 int x = v[u][0]; 33 for(int i=0;i<3;i++) 34 { 35 LL val = 0,minv = (1ll<<63)-1; 36 for(int j=0;j<3;j++) 37 if(i!=j) val = max(f[x][j][0],val),minv = min(f[x][j][1],minv); 38 f[u][i][0]+=val; 39 f[u][i][1]+=minv; 40 } 41 }else if(v[u].size()==2) 42 { 43 int x = v[u][0],y = v[u][1]; 44 for(int i=0;i<3;i++) 45 { 46 LL val = 0,minv = (1ll<<63)-1; 47 for(int j=0;j<3;j++) 48 for(int k=0;k<3;k++) 49 if(i!=j&&j!=k&&k!=i) 50 val=max(f[x][j][0]+f[y][k][0],val),minv = min(f[x][j][1]+f[y][k][1],minv); 51 f[u][i][0]+=val; 52 f[u][i][1]+=minv; 53 } 54 } 55 } 56 int main() 57 { 58 scanf("%s",s+1); 59 len = strlen(s+1); 60 build(1); 61 dfs(1); 62 LL maxn = 0,minv = (1ll<<63)-1; 63 for(int i=0;i<3;i++) maxn = max(f[1][i][0],maxn),minv= min(f[1][i][1],minv); 64 printf("%lld %lld\n",maxn,minv); 65 return 0; 66 }