[BZOJ4446][SCOI2015]小凸玩密室(树形DP)

密室玩小凸。

完全二叉树关于复杂度的两个性质:

1.所有点的深度和为$O(n\log n)$

2.所有点的子树内的叶子个数和为$O(n\log n)$

根据这两个性质可以分别解决此题。

下面使用第二个性质,参考:https://www.cnblogs.com/Gloid/p/9874570.html

f[i][j]表示从i点开始,遍历i的子树,最后在j停止的最优解(其中j为i的子树中的某个叶子)。

g[i][j]表示从i的子树中某个点开始,遍历i的子树,最后在j停止的最优解。

f转移考虑四种情况:

  点亮左子树,点亮i,点亮右子树,或反之。

  点亮i,点亮左子树,点亮右子树,或反之。

g转移考虑同样的四种情况,再与f取min。

注意当i为叶子或只有一个儿子时特殊处理。

细节要考虑清楚,为了保证空间使用vector记录子树内的叶子。

小凸玩我。

 1 #include<cstdio>
 2 #include<vector>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=200010;
 9 const ll inf=1e16;
10 int n,x;
11 ll ans,v[N],rlen[N],llen[N],d[N];
12 vector<int>son[N];
13 vector<ll>f[N],g[N];
14 
15 void dfs(int x){
16     int ls=x<<1,rs=ls|1;
17     if (ls>n){ son[x].push_back(x); f[x].push_back(0); g[x].push_back(0); return; }
18     d[ls]=d[x]+llen[x]; dfs(ls);
19     if (rs>n){
20         int lm=(int)son[ls].size()-1; ll mn=inf;
21         rep(i,0,lm) son[x].push_back(son[ls][i]),mn=min(mn,f[ls][i]+(d[son[ls][i]]-d[x])*v[x]);
22         rep(i,0,lm) f[x].push_back(f[ls][i]+llen[x]*v[ls]),g[x].push_back(f[x][i]);
23         son[x].push_back(x); f[x].push_back(inf); g[x].push_back(mn);
24         return;
25     }
26     d[rs]=d[x]+rlen[x]; dfs(rs);
27     int lm=son[ls].size()-1,rm=son[rs].size()-1;
28     ll mn1=inf,mn2=inf,mn3=inf,mn4=inf;
29     rep(i,0,lm) son[x].push_back(son[ls][i]),mn1=min(mn1,f[ls][i]+(d[son[ls][i]]+d[rs]-2*d[x])*v[rs]);
30     rep(i,0,rm) son[x].push_back(son[rs][i]),mn2=min(mn2,f[rs][i]+(d[son[rs][i]]+d[ls]-2*d[x])*v[ls]);
31     rep(i,0,lm) f[x].push_back(rlen[x]*v[rs]+mn2+f[ls][i]),mn3=min(mn3,g[ls][i]+(d[son[ls][i]]-d[x])*v[x]);
32     rep(i,0,rm) f[x].push_back(llen[x]*v[ls]+mn1+f[rs][i]),mn4=min(mn4,g[rs][i]+(d[son[rs][i]]-d[x])*v[x]);
33     rep(i,0,lm) g[x].push_back(min(mn4+llen[x]*v[ls]+f[ls][i],f[x][i]));
34     rep(i,0,rm) g[x].push_back(min(mn3+rlen[x]*v[rs]+f[rs][i],f[x][lm+i+1]));
35 }
36 
37 int main(){
38     freopen("bzoj4446.in","r",stdin);
39     freopen("bzoj4446.out","w",stdout);
40     scanf("%d",&n);
41     rep(i,1,n) scanf("%lld",&v[i]);
42     rep(i,2,n){
43         scanf("%d",&x);
44         if (i&1) rlen[i/2]=x; else llen[i/2]=x;
45     }
46     dfs(1); ans=inf; int tmp=(int)g[1].size()-1;
47     rep(i,0,tmp) ans=min(ans,g[1][i]);
48     printf("%lld\n",ans);
49     return 0;
50 }

猜你喜欢

转载自www.cnblogs.com/HocRiser/p/9878608.html