POJ3585 換根模板
阿新 • • 發佈:2018-10-18
case sizeof sin clu inline print edge ont poj
題意:機翻?
好,假裝各位都已經看懂了題。
首先是暴力,枚舉每一個點作為根,然後每次做一個樹上DP,復雜度O(n2),T掉;
然後,我們考慮怎樣優化。
假設我們已經求出了x的答案,對與每一個它的子節點,
我們註意到其實當我們換其子節點y為根時,y的子樹貢獻是已知的。
只需考慮另外一側的貢獻之間,
同時又註意到,除y以外的對x的貢獻就是x的答案減掉y對它的貢獻,也是一定的。
所以只有x會影響到y,直接根據限制在y和x之間轉移一下就好了。
#include <cstdio> #include <cstring> #include <string> using namespacestd; 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; }
POJ3585 換根模板