zoukankan      html  css  js  c++  java
  • 【HEOI 2018】林克卡特树

    转载请注明出处:http://www.cnblogs.com/TSHugh/p/8776179.html

    先说60分的.
    思路题解上很清晰:

    问题似乎等价于选K+1条点不相交的链哎!
    F(x,k,0/1/2)表示考虑以x为根的子树,选了k条链,点x的度数为0/1/2的最优解.

    我说一下比较坑的地方吧:
    1.初始化要-Inf(反正我不加这个会wa)
    2.注意转移的顺序
    3.别忘了突然出现新的路径或者突然消失了一个路径的时侯加减1
    4.一定要割k下
    细节说多不多,说少不少,还得自己打.
    说一下100分的.
    60分的瓶颈在于k,那么如果对于k没有限制的话,那么我们的转移就会变成O(n)的(和60分的dp是差不多的).
    如何去掉k的限制呢,我们考虑,我们的答案数组关于下标是凸包(想一下就会发现很显然啊).那么我们想到凸包就会想卡他,那么也就是我们设斜率去卡到k,那么我们有了斜率会发生什么呢.
    我们的问题转化为了——设斜率为cost,那么就是求,这棵树选取若干条不相交路径,得到的贡献是路径边权和,代价是每条路径花费cost,求最终答案(最大化收益),及其路径条数.
    这样我们每次二分出斜率之后会O(n)出解,得到路径条数,从而继续二分.
    不难打,有了60分的dp之后,给到二分斜率的思路就应该可以写出来了.

    (补充一下:这玩意似乎是wqs二分……)

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    char xB[(1<<15)+10],*xS,*xT;
    #define gtc() (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
    inline void read(int &x){
        register char ch=gtc();
        bool ud=false;
        for(x=0;ch<'0'||ch>'9';ch=gtc())
            if(ch=='-')
                ud=true;
        for(;ch>='0'&&ch<='9';ch=gtc())
            x=x*10+ch-'0';
        if(ud)x=-x;
    }
    typedef long long LL;
    const int N=300010;
    const LL Inf=1e15;
    struct V{
      int to,next,w;
    }c[N<<1];
    int head[N],t;
    inline void add(int x,int y,int z){
      c[++t].to=y,c[t].next=head[x],head[x]=t,c[t].w=z;
    }
    int n;
    LL k;
    struct A{
      int x;LL y;
      inline void reset(){x=0,y=0;}
      inline void set(){x=0,y=-Inf;}
      inline A up(){
        A ret=*this;
        ++ret.x,ret.y-=k;
        return ret;
      }
      inline void cover(A a){
        if(a.y>y||(a.y==y&&a.x<x))
          (*this)=a;
      }
      inline void cover(A a,A b){
        if(a.y==-Inf||b.y==-Inf)return;
        a.x+=b.x,a.y+=b.y;
        cover(a);
      }
      inline void cover(A a,A b,LL w,int opt){
        if(a.y==-Inf||b.y==-Inf)return;
        a.x+=b.x-opt,a.y+=b.y+w+(opt?k:0);
        if(a.x<=0)return;
        cover(a);
      }
    }f[N][3];
    inline void dfs(int x,int fa){
      int i,v;
      f[x][0].reset();
      f[x][1].set();
      f[x][2].set();
      for(i=head[x];i;i=c[i].next){
        v=c[i].to;
        if(v==fa)continue;
        dfs(v,x);
        f[x][2].cover(f[x][2],f[v][2]);
        f[x][2].cover(f[x][1],f[v][1],c[i].w,1);
        f[x][1].cover(f[x][1],f[v][2]);
        f[x][1].cover(f[x][0],f[v][1],c[i].w,0);
        f[x][0].cover(f[x][0],f[v][2]);
      }
      f[x][1].cover(f[x][0].up());
      f[x][2].cover(f[x][1]);
      f[x][2].cover(f[x][0]);
    }
    inline A solve(){
      dfs(1,0);
      return f[1][2];
    }
    int main(){
      int need;
      read(n),read(need);
      ++need;
      int i,x,y,z;
      for(i=1;i<n;++i){
        read(x),read(y),read(z);
        add(x,y,z),add(y,x,z);
      }
      LL l=-1e12,r=1e12,mid,ans=0;
      A ret;
      while(l<=r){
        k=mid=l+r>>1;
        ret=solve();
        if(ret.x<=need)
          ans=ret.y+need*k,r=mid-1;
        else
          l=mid+1;
      }
      printf("%lld
    ",ans);
      return 0;
    }
    Kod
  • 相关阅读:
    【转】卡特兰数四个公式(简单)
    【基础算法-ST表】入门 -C++
    【题解】[Nwerc 2006]escape -C++
    C#高级编程第11版
    C#高级编程第11版
    C#高级编程第11版
    C#高级编程第11版
    C#高级编程第11版
    109th LeetCode Weekly Contest Knight Dialer
    109th LeetCode Weekly Contest Number of Recent Calls
  • 原文地址:https://www.cnblogs.com/TSHugh/p/8776179.html
Copyright © 2011-2022 走看看