【HEOI 2018】林克卡特樹

轉載請註明出處:http://www.cnblogs.com/TSHugh/p/8776179.htmlhtml

先說60分的.
思路題解上很清晰:數組

問題彷佛等價於選K+1條點不相交的鏈哎!
F(x,k,0/1/2)表示考慮以x爲根的子樹,選了k條鏈,點x的度數爲0/1/2的最優解.ide

我說一下比較坑的地方吧:
1.初始化要-Inf(反正我不加這個會wa)
2.注意轉移的順序
3.別忘了忽然出現新的路徑或者忽然消失了一個路徑的時侯加減1
4.必定要割k下
細節說多很少,說少很多,還得本身打.
說一下100分的.
60分的瓶頸在於k,那麼若是對於k沒有限制的話,那麼咱們的轉移就會變成O(n)的(和60分的dp是差很少的).
如何去掉k的限制呢,咱們考慮,咱們的答案數組關於下標是凸包(想一下就會發現很顯然啊).那麼咱們想到凸包就會想卡他,那麼也就是咱們設斜率去卡到k,那麼咱們有了斜率會發生什麼呢.
咱們的問題轉化爲了——設斜率爲cost,那麼就是求,這棵樹選取若干條不相交路徑,獲得的貢獻是路徑邊權和,代價是每條路徑花費cost,求最終答案(最大化收益),及其路徑條數.
這樣咱們每次二分出斜率以後會O(n)出解,獲得路徑條數,從而繼續二分.
不難打,有了60分的dp以後,給到二分斜率的思路就應該能夠寫出來了.this

(補充一下:這玩意彷佛是wqs二分……)spa

#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\n",ans);
  return 0;
}
Kod
相關文章
相關標籤/搜索