codeforces 671D
首先O(n2)dp很好想
f[i][j]表示i子树内的所有边都被覆盖且i~j的路径也都被覆盖的最小花费。
考虑去掉无用的状态,其实真正用到的就是每一条链。
去掉第二维,f[i]表示i子树内的边都被覆盖且父向边也被覆盖的最小花费。
那么怎么转移呢?
f[i]可以是任意一条包含i和fa[i]的链转移而来,
首先要选这条链,还要加上这条链下端点到i所有其他儿子的f值,这样复杂度好像依旧很高
再优化,这不就是线段树取一个min吗?
那么我们现在要做的就是在每一个点上,在对应的一些链中取一个min
对于每条链,它是在它的下端点之上开始做出贡献的,
所以每个点控制的区间要是它的子树中所有向上连的边
当我们搞点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 }
人生如梦亦如幻 朝如晨露暮如霞。