首先O(n2)dp很好想ios
f[i][j]表示i子樹內的全部邊都被覆蓋且i~j的路徑也都被覆蓋的最小花費。ide
考慮去掉無用的狀態,其實真正用到的就是每一條鏈。優化
去掉第二維,f[i]表示i子樹內的邊都被覆蓋且父向邊也被覆蓋的最小花費。spa
那麼怎麼轉移呢?code
f[i]能夠是任意一條包含i和fa[i]的鏈轉移而來,blog
首先要選這條鏈,還要加上這條鏈下端點到i全部其餘兒子的f值,這樣複雜度好像依舊很高string
再優化,這不就是線段樹取一個min嗎?it
那麼咱們如今要作的就是在每個點上,在對應的一些鏈中取一個minio
對於每條鏈,它是在它的下端點之上開始作出貢獻的,event
因此每一個點控制的區間要是它的子樹中全部向上連的邊
當咱們搞點x時,首先要算出他全部兒子的f值加和sum.而後要將以x爲下端點的鏈的值更新爲sum+c[i],還要將全部以x爲上端點的鏈賦值inf,還要對其全部兒子的控制的鏈都加上sum-f[son],最後對於他控制的全部鏈取一個min就行了.
代碼
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #define N 300005 7 #define inf 1000000000000000ll 8 #define LL long long 9 using namespace std; 10 int n,m,c[N]; 11 int e=1,head[N],out[N],in[N]; 12 struct edge{int v,next;}ed[4*N]; 13 void add(int u,int v,int *h){ 14 ed[e]=(edge){v,h[u]}; 15 h[u]=e++; 16 } 17 int L[N],R[N],tot,d[N]; 18 void dfs(int x,int fa){ 19 L[x]=tot+1; 20 for(int i=in[x];i;i=ed[i].next) 21 d[ed[i].v]=++tot; 22 for(int i=head[x];i;i=ed[i].next) 23 if(ed[i].v!=fa)dfs(ed[i].v,x); 24 R[x]=tot; 25 } 26 LL f[N]; 27 LL minn[4*N],lazy[4*N]; 28 void update(int rt,int l,int r,int x,LL y){ 29 if(l==r){minn[rt]=y;return ;} 30 int mid=(l+r)>>1; 31 if(x<=mid)update(rt<<1,l,mid,x,y); 32 else update(rt<<1|1,mid+1,r,x,y); 33 minn[rt]=min(min(minn[rt<<1],minn[rt<<1|1])+lazy[rt],inf); 34 } 35 void add(int rt,int l,int r,int x,int y,LL z){ 36 if(x<=l&&r<=y){lazy[rt]+=z;minn[rt]+=z;return ;} 37 int mid=(l+r)>>1; 38 if(x<=mid) add(rt<<1,l,mid,x,y,z); 39 if(y>mid) add(rt<<1|1,mid+1,r,x,y,z); 40 minn[rt]=min(min(minn[rt<<1],minn[rt<<1|1])+lazy[rt],inf); 41 } 42 LL query(int rt,int l,int r,int x,int y){ 43 if(x<=l&&r<=y) return minn[rt]; 44 LL ans=inf; 45 int mid=(l+r)>>1; 46 if(x<=mid)ans=min(ans,query(rt<<1,l,mid,x,y)); 47 if(y>mid) ans=min(ans,query(rt<<1|1,mid+1,r,x,y)); 48 return min(ans+lazy[rt],inf); 49 } 50 void solve(int x,int fa){ 51 LL ans=0; 52 for(int i=head[x];i;i=ed[i].next){ 53 if(ed[i].v==fa)continue; 54 solve(ed[i].v,x); 55 ans=min(f[ed[i].v]+ans,inf); 56 } 57 if(x==1){f[1]=ans;return;} 58 for(int i=in[x];i;i=ed[i].next) 59 update(1,1,m,d[ed[i].v],ans+c[ed[i].v]); 60 for(int i=out[x];i;i=ed[i].next) 61 update(1,1,m,d[ed[i].v],inf); 62 for(int i=head[x];i;i=ed[i].next){ 63 if(ed[i].v==fa)continue; 64 add(1,1,m,L[ed[i].v],R[ed[i].v],ans-f[ed[i].v]); 65 } 66 f[x]=query(1,1,m,L[x],R[x]); 67 } 68 69 int main(){ 70 scanf("%d%d",&n,&m); 71 for(int i=1,u,v;i<n;i++){ 72 scanf("%d%d",&u,&v); 73 add(u,v,head); 74 add(v,u,head); 75 } 76 for(int i=1,u,v;i<=m;i++){ 77 scanf("%d%d%d",&u,&v,&c[i]); 78 add(u,i,in); 79 add(v,i,out); 80 } 81 dfs(1,0); 82 memset(minn,0x15f,sizeof minn); 83 memset(lazy,0,sizeof lazy); 84 solve(1,0); 85 if(f[1]>=inf)printf("-1\n"); 86 else printf("%lld\n",f[1]); 87 return 0; 88 }