• 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
    ");
    86     else printf("%lld
    ",f[1]);
    87     return 0;
    88 }
    youmu
  • 相关阅读:
    centos 用户指定目录访问
    centos FTP 用户指定目录禁用上级目录
    centos下SVN搭建多个库文件总汇
    listview点击checkbox,修改值
    C#转成时间格式
    nmap 查看主机上开放的端口
    xargs、管道、exec区别
    OSI七层模型,作用及其对应的协议
    linux面试题(重点)
    数据库备份还原 mysqldump
  • 原文地址:https://www.cnblogs.com/Ren-Ivan/p/7750414.html
Copyright © 2020-2023  润新知