1. 程式人生 > >POJ3585 換根模板

POJ3585 換根模板

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 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; }

POJ3585 換根模板