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

 

posted @ 2017-10-29 16:52  Ren_Ivan  阅读(623)  评论(0编辑  收藏  举报