test20181029 宝藏
题意
分析
考场做法
一眼看出是支持换根的树形dp。
用f(x,0/1)表示x及其子树中,从x出发,不一定/一定回到x的最大收益。
然后子树很好做。
换根的时候,我先计算后还原,需要考虑很多,调了很久。
后来知道可以用up,down状态转移,会好写一些,但要考虑得跟我先前打的差不多。
#include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<string> #include<vector> #include<list> #include<deque> #include<stack> #include<queue> #include<map> #include<set> #include<bitset> #include<algorithm> #include<complex> #include<cassert> #define rg register #define il inline #define co const #pragma GCC optimize ("O0") using namespace std; template<class T> il T read() { T data=0; int w=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') w=-1; ch=getchar(); } while(isdigit(ch)) data=10*data+ch-'0',ch=getchar(); return data*w; } template<class T> il T read(T&x) { return x=read<T>(); } typedef long long ll; const int INF=0x7fffffff; co int MAXN=3e5+7; struct Edge { int nx,to,w; }E[MAXN<<1]; int head[MAXN],ecnt; il void addedge(rg int x,rg int y,rg int w) { E[++ecnt].to=y,E[ecnt].w=w; E[ecnt].nx=head[x],head[x]=ecnt; } int fa[MAXN],fw[MAXN]; int val[MAXN]; ll f[MAXN][2]; int maxv[MAXN],secv[MAXN]; il ll take(rg int y) { return max(0LL,f[y][0]-fw[y]); } il ll fetch(rg int y) { return max(0LL,f[y][1]-2*fw[y]); } il ll calc(rg int y) { return take(y)-fetch(y); } il void dfs1(rg int x,rg int fath) { fa[x]=fath; f[x][1]=val[x]; for(rg int i=head[x];i;i=E[i].nx) { rg int y=E[i].to,w=E[i].w; if(y==fath) { fw[x]=w; continue; } dfs1(y,x); f[x][1]+=fetch(y); } f[x][0]=f[x][1]; for(rg int i=head[x];i;i=E[i].nx) { rg int y=E[i].to; if(y==fath) continue; if(calc(y)>calc(secv[x])) { secv[x]=y; if(calc(secv[x])>calc(maxv[x])) swap(secv[x],maxv[x]); } } f[x][0]+=calc(maxv[x]); } ll fet[MAXN],calsec[MAXN],cal[MAXN]; il void dfs2(rg int x) { if(fa[x]) { // f[fa] shouldn't change fet[x]=fetch(x); cal[x]=calc(x); f[fa[x]][1]-=fet[x]; f[fa[x]][0]-=fet[x]; rg int w=fw[fa[x]]; fw[fa[x]]=fw[x]; f[x][1]+=fetch(fa[x]); f[x][0]=f[x][1]; if(maxv[fa[x]]==x) { f[fa[x]][0]-=cal[x]; f[fa[x]][0]+=calsec[fa[x]]; } if(calc(fa[x])>calc(secv[x])) { secv[x]=fa[x]; if(calc(secv[x])>calc(maxv[x])) swap(secv[x],maxv[x]); } calsec[x]=calc(secv[x]); f[x][0]+=calc(maxv[x]); f[fa[x]][1]+=fet[x]; // restore f[fa[x]][0]+=fet[x]; fw[fa[x]]=w; if(maxv[fa[x]]==x) { f[fa[x]][0]-=calsec[fa[x]]; f[fa[x]][0]+=cal[x]; } } else { fet[x]=fetch(x); calsec[x]=calc(secv[x]); cal[x]=calc(x); } for(rg int i=head[x];i;i=E[i].nx) { rg int y=E[i].to; if(y==fa[x]) continue; dfs2(y); } } int main() { freopen("treasure.in","r",stdin); freopen("treasure.out","w",stdout); rg int n=read<int>(); for(rg int i=1;i<n;++i) { rg int x=read<int>(),y=read<int>(),w=read<int>(); addedge(x,y,w); addedge(y,x,w); } for(rg int i=1;i<=n;++i) { read(val[i]); } dfs1(1,0); dfs2(1); /* for(int i=1;i<=n;++i) { printf("%d:\n",i); printf(" f0=%lld\tf1=%lld\n",f[i][0],f[i][1]); }*/ for(rg int i=1;i<=n;++i) { printf("%lld\n",f[i][0]); } // fclose(stdin); // fclose(stdout); return 0; }
标解
#include <iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<cstdlib> #include<bitset> using namespace std; typedef long long ll; const int N=610000; int fi[N],ne[N],len[N],to[N]; ll dp0[N],dp1[N]; ll ans[N],wushi0[N],wushi1[N],val[N]; int pE,n; //0:考虑回到原点;1:不回到原点 void addE(int u,int v,int l) { pE++;to[pE]=v;len[pE]=l; ne[pE]=fi[u];fi[u]=pE; } void dfs(int u,int fa) { ll mx=0; for (int j=fi[u];j;j=ne[j]) { if (to[j]==fa) continue; dfs(to[j],u); if (dp0[to[j]]-2*len[j]>0) { dp0[u]+=dp0[to[j]]-2*len[j]; mx=max(mx,len[j]+dp1[to[j]]-dp0[to[j]]); } else mx=max(mx,dp1[to[j]]-len[j]); } dp0[u]+=val[u]; dp1[u]=dp0[u]+mx; } void dfs2(int u,int fa,int le) { ans[u]=max(dp0[u]+max(wushi1[u]-le,(ll)0),dp1[u]+max(wushi0[u]-le*2,(ll)0)); ll mx1=0,mx2=0; for (int j=fi[u];j;j=ne[j]) { if (to[j]==fa) continue; ll now; if (dp0[to[j]]-2*len[j]>0) now=len[j]+dp1[to[j]]-dp0[to[j]]; else now=dp1[to[j]]-len[j]; if (now>mx1) {mx2=mx1;mx1=now;} else if (now>mx2) mx2=now; } ll now; if (wushi0[u]-2*le>0) now=le+wushi1[u]-wushi0[u]; else now=wushi1[u]-le; if (now>mx1) {mx2=mx1;mx1=now;} else if (now>mx2) mx2=now; for (int j=fi[u];j;j=ne[j]) { if (to[j]==fa) continue; wushi0[to[j]]=dp0[u]-max((ll)0,dp0[to[j]]-2*len[j])+max((ll)0,wushi0[u]-2*le); ll now; if (dp0[to[j]]-2*len[j]>0) now=len[j]+dp1[to[j]]-dp0[to[j]]; else now=dp1[to[j]]-len[j]; if (now==mx1) wushi1[to[j]]=wushi0[to[j]]+mx2; else wushi1[to[j]]=wushi0[to[j]]+mx1; } for (int j=fi[u];j;j=ne[j]) if (to[j]!=fa) dfs2(to[j],u,len[j]); } int main() { freopen("treasure.in","r",stdin); freopen("treasure.out","w",stdout); scanf("%d",&n); for (int i=1;i<n;i++) { int u,v,l;scanf("%d%d%d",&u,&v,&l); addE(u,v,l);addE(v,u,l); } for (int i=1;i<=n;i++) scanf("%d",&val[i]); dfs(1,0); for (int j=fi[1];j;j=ne[j]) if (dp0[to[j]]-2*len[j]>0) wushi0[to[j]]=dp0[1]-(dp0[to[j]]-2*len[j]); else wushi0[to[j]]=dp0[1]; ll mx1=0,mx2=0; for (int j=fi[1];j;j=ne[j]) { ll now; if (dp0[to[j]]-2*len[j]>0) now=len[j]+dp1[to[j]]-dp0[to[j]]; else now=dp1[to[j]]-len[j]; if (now>mx1) {mx2=mx1;mx1=now;} else if (now>mx2) mx2=now; } for (int j=fi[1];j;j=ne[j]) { ll now; if (dp0[to[j]]-2*len[j]>0) now=len[j]+dp1[to[j]]-dp0[to[j]]; else now=dp1[to[j]]-len[j]; if (now==mx1) wushi1[to[j]]=wushi0[to[j]]+mx2; else wushi1[to[j]]=wushi0[to[j]]+mx1; } ans[1]=dp1[1]; for (int j=fi[1];j;j=ne[j]) dfs2(to[j],1,len[j]); for (int i=1;i<=n;i++) printf("%lld\n",ans[i]); return 0; }
静渊以有谋,疏通而知事。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步