【HEOI 2018】林克卡特树

先说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之后,给到二分斜率的思路就应该可以写出来了.

#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

原文地址:https://www.cnblogs.com/TSHugh/p/8776179.html

时间: 2024-08-11 19:25:49

【HEOI 2018】林克卡特树的相关文章

[九省联考2018]林克卡特树(DP+wqs二分)

对于k=0和k=1的点,可以直接求树的直径. 然后对于60分,有一个重要的转化:就是求在树中找出k+1条点不相交的链后的最大连续边权和. 这个DP就好.$O(nk^2)$ 然后我们完全不可以想到,将best[k](选择k条链的答案)打表输出,更不可能然后作差分,发现得到的数组是递减的. 这说明:best[k]是一个上凸包. 于是我们可以二分一个斜率去切这个凸包(类似导数),根据切点横坐标与k的大小旋转直线(改变斜率). 考虑给你一个直线斜率k,怎么找到它和凸包的切点.实际上就相当于将这个凸函数减

[八省联考2018]林克卡特树

题目描述 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做"LCT" 的挑战,它的规则是这样子的:现在有一个N 个点的 树(Tree),每条边有一个整数边权vi ,若vi >= 0,表示走这条边会获得vi 的收益:若vi < 0 ,则表示走这条边需要支付- vi 的过路费.小L 需要控制主角Link 切掉(Cut)树上的 恰好K 条边,然后再连接 K

解题:八省联考2018 林克卡特树

题面 DP凸优化 题目并不难 先转化问题,显然k=0的时候我们都知道是求直径,然后k=1就是选两条点不相交的链拼起来,很容易推出题目就是要我们在树上选$k+1$条点不相交的链 事实上你直接按照边不相交做,取k+1次直径都可以得到50pts的好成绩,我佛了(不要问我怎么知道的 这个东西是可以DP的(稍微有点麻烦):设$dp[i][j][0/1/2]$表示以$i$为根的子树里选出j条链,这时i的度数为0/1/2的最优解.度数为零表示i是单独一个点,度数为1表示是链的端点,度数为2就是链中间的一个点

P4383 [八省联考2018]林克卡特树lct 树形DP+凸优化/带权二分

$ \color{#0066ff}{ 题目描述 }$ 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做"LCT" 的挑战,它的规则是这样子的:现在有一个N 个点的 树(Tree),每条边有一个整数边权vi ,若vi >= 0,表示走这条边会获得vi 的收益:若vi < 0 ,则表示走这条边需要支付- vi 的过路费.小L 需要控制主角Link 切掉(

[八省联考2018]林克卡特树lct

#include<bits/stdc++.h> #define RG register #define IL inline #define _ 500005 #define INF 1e18 #define ll long long using namespace std; IL ll gi(){ RG ll data = 0 , m = 1; RG char ch = 0; while(ch != '-' && (ch<'0' || ch > '9')) ch =

bzoj5252 [2018多省省队联测]林克卡特树

斜率优化树形dp?? 我们先将问题转化成在树上选K+1条互不相交路径,使其权值和最大. 然后我们考虑60分的dp,直接维护每个点子树内选了几条路径,然后该点和0/1/2条路径相连 然后我们会发现最后的答案关于割的边数是一个单峰的函数,这时候事情就变得明朗起来个p 我们考虑拿一条斜率为k的直线去切这个函数,切到的点是什么?是每选一条路径额外付出k点代价时的最优解,于是我们二分这个斜率,然后直接树形dp求最优解以及位置即可,因为每次的最优解一定是上次的最优解和儿子的最优解共同转移而来的,所以我们只需

[loj 2478][luogu P4843]「九省联考 2018」林克卡特树

传送门 Description 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做"LCT" 的挑战,它的规则是这样子的:现在有一个N 个点的 树(Tree),每条边有一个整数边权vi ,若vi >= 0,表示走这条边会获得vi 的收益:若vi < 0 ,则表示走这条边需要支付- vi 的过路费.小L 需要控制主角Link 切掉(Cut)树上的 恰好K

2018知到智慧树珍奇观赏植物答案知到珍奇观赏植物考试答案

网络选修课珍奇观赏植物答案第一章单元测试1[单选题](10分)在IUCN红色名录中,CR表示 B A. 灭绝 B. 极危 C. 濒危 D. 易危-----------------需要购买完整版答案联系Q+-Q 64315052-----------------2[单选题](10分)水杉学名中的命名人"Hu"是指植物学家C A. 胡文光 B. 胡秀英 C. 胡先骕 D. 胡志浩3[单选题](10分)1869年,法国传教士和自然科学家戴维(A.David)在四川宝兴县发现了什么植物? C

【HEOI 2018】制胡窜

YJQ的题解把思路介绍得很明白,只不过有些细节说得还是太笼统了(不过正经的题解就应该这个样子吧).我的思路和YJQ有一些不同.首先: 考虑反过来,求三个串都不包含询问串的方案数,这样需要的讨论会少很多.不难发现,三个串都不包含询问串的方案,就是询问串每个出现位置里(这里的位置指的是整个串,不是右端点),都至少含有一个断点的方案数.(本段落来自YJQ题解) 然后: 可以发现割的话一定是把原来的一群线段分为两波(其中某一波可以为0),假设左边的那刀为第一刀,右边的那刀为第二刀,第一波均由第一刀砍断,