BZOJ4446 SCOI2015小凸玩密室(树形dp)
设f[i][j]为由根进入遍历完i子树,最后一个到达的点是j时的最小代价,g[i][j]为由子树内任意一点开始遍历完i子树,最后一个到达的点是j时的最小代价,因为是一棵完全二叉树,状态数量是nlogn的。转移考虑四种走法:根→左子树→右子树;根→右子树→左子树;左子树→根→右子树;右子树→根→左子树 即可。好像和大多数题解不一样,明明感觉这种做法比较显然。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 200010 #define inf 100000000000000000ll int n,a[N],p[N],deep[N],t; vector<int> son[N]; vector<long long> f[N],g[N]; struct data{int to,nxt,len; }edge[N]; void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;} void dfs(int k) { int cnt=0; for (int i=p[k];i;i=edge[i].nxt) { cnt++; deep[edge[i].to]=deep[k]+edge[i].len; dfs(edge[i].to); for (int j=0;j<son[edge[i].to].size();j++) son[k].push_back(son[edge[i].to][j]); } son[k].push_back(k); if (cnt==0) {f[k].push_back(0);g[k].push_back(0);return;} if (cnt==1) { long long v=inf; for (int i=0;i<son[k].size()-1;i++) f[k].push_back(f[edge[p[k]].to][i]+1ll*edge[p[k]].len*a[edge[p[k]].to]), g[k].push_back(f[k][i]),v=min(v,f[edge[p[k]].to][i]+1ll*(deep[son[edge[p[k]].to][i]]-deep[k])*a[k]); f[k].push_back(inf),g[k].push_back(v); } else { long long P=inf,Q=inf,X=inf,Y=inf; int x=edge[p[k]].to,y=edge[edge[p[k]].nxt].to,w=edge[p[k]].len,v=edge[edge[p[k]].nxt].len; for (int i=0;i<son[x].size();i++) P=min(P,f[x][i]+1ll*w*a[x]+1ll*(deep[son[x][i]]-deep[k])*a[y]), X=min(X,g[x][i]+1ll*(deep[son[x][i]]-deep[k])*a[k]); for (int i=0;i<son[y].size();i++) Q=min(Q,f[y][i]+1ll*v*a[y]+1ll*(deep[son[y][i]]-deep[k])*a[x]), Y=min(Y,g[y][i]+1ll*(deep[son[y][i]]-deep[k])*a[k]); X=min(X,P),Y=min(Y,Q); for (int i=0;i<son[x].size();i++) f[k].push_back(Q+1ll*w*a[x]+f[x][i]),g[k].push_back(Y+1ll*w*a[x]+f[x][i]); for (int i=0;i<son[y].size();i++) f[k].push_back(P+1ll*v*a[y]+f[y][i]),g[k].push_back(X+1ll*v*a[y]+f[y][i]); f[k].push_back(inf),g[k].push_back(inf); } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4446.in","r",stdin); freopen("bzoj4446.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<n;i++) addedge(i+1>>1,i+1,read()); dfs(1); long long ans=inf; for (int i=0;i<son[1].size();i++) ans=min(ans,g[1][i]); cout<<ans; return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步