题意:机翻?
好,假装各位都已经看懂了题。
首先是暴力,枚举每一个点作为根,然后每次做一个树上DP,复杂度O(n2),T掉;
然后,我们考虑怎样优化。
假设我们已经求出了x的答案,对与每一个它的子节点,
我们注意到其实当我们换其子节点y为根时,y的子树贡献是已知的。
只需考虑另外一侧的贡献之间,
同时又注意到,除y以外的对x的贡献就是x的答案减掉y对它的贡献,也是一定的。
所以只有x会影响到y,直接根据限制在y和x之间转移一下就好了。
#include <cstdio> #include <cstring> #include <string> using namespace std; inline int gi () { int x=0, w=0; char ch=0; while (! (ch>=‘0‘ && ch<=‘9‘) ) { if (ch==‘-‘) w=1; ch=getchar (); } while (ch>=‘0‘ && ch<=‘9‘) { x= (x<<3) + (x<<1) + (ch^48); ch=getchar (); } return w?-x:x; } const int N=2e5+10; int T,n,tot,ans,head[N],f[N],Deg[N],ind[N],vis[N]; struct Edge { int next, now, val; }e[N<<1]; inline void make (int from, int to, int va) { e[++tot].next=head[from]; e[tot].now=to; e[tot].val=va; head[from]=tot; } void New_case () { tot=0; ans=0; memset (f, 0, sizeof (f) ); memset (&e, 0, sizeof (e) ); memset (ind, 0, sizeof (ind) ); memset (vis, 0, sizeof (vis) ); memset (Deg, 0, sizeof (Deg) ); memset (head, 0, sizeof (head) ); } void DP (int k) { vis[k]=1; for (int i=head[k];i;i=e[i].next) { int x=e[i].now; if (vis[x]) continue; DP (x); if (ind[x]==1) Deg[k]+=e[i].val; else Deg[k]+=min (Deg[x], e[i].val); } } void DFS (int p) { vis[p]=1; for (int i=head[p];i;i=e[i].next) { int k=e[i].now; if (vis[k]) continue; if (ind[p]==1) f[k]=Deg[k]+e[i].val; else f[k]=Deg[k]+min (e[i].val, f[p]-min (e[i].val, Deg[k]) ); DFS (k); } } int main () { T=gi (); while (T--) { n=gi (); New_case (); for (int i=1, x, y, z;i<n;++i) { x=gi (), y=gi (), z=gi (); ind[x]++, ind[y]++; make (x, y, z); make (y, x, z); } DP (1); memset (vis, 0, sizeof (vis) ); f[1]=Deg[1]; DFS (1); // 换根 for (int i=1;i<=n;++i) ans=max (ans, f[i]); printf ("%d\n", ans); } return 0; }
原文地址:https://www.cnblogs.com/Bhllx/p/9807605.html
时间: 2024-10-11 00:40:13