zoukankan      html  css  js  c++  java
  • [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 条边,然后再连接 K 条边权为 0 的边,得到一棵新的树。接着,他会选择树上的两个点p; q ,并沿着树上连接这两点的简单路径从p 走到q ,并为经过的每条边支付过路费/ 获取相应收益。

    海拉鲁大陆之神TemporaryDO 想考验一下Link。他告诉Link,如果Link 能切掉 合适的边、选择合适的路径从而使 总收益 - 总过路费最大化的话,就把传说中的大师之剑送给他。

    小 L 想得到大师之剑,于是他找到了你来帮忙,请你告诉他,Link 能得到的 总收益 - 总过路费最大是多少。

    Solution

    原题转化为树上求K+1条不相交路径的最大权值和

    是一道WQS二分裸题

    首先,可以很容易的写出一个树形dp

    然后根据wqs的套路,给每条路径的权值和+add

    在计算最大权值和时,我们应当考虑让选到的边数尽可能的大

    其实就是在写树d的时候适当注意一下顺序就行

    然后,WQS二分出的应该时最小的——使得所选点数(geq K+1)的add


    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    const ll inf=3e11,MN=3e5+5;
    int N,K,hr[MN],en;
    struct edge{int to;ll w;int nex;}e[MN<<1];
    inline void ins(int f,int t,int w)
    {
    	e[++en]=(edge){t,w,hr[f]};hr[f]=en;
    	e[++en]=(edge){f,w,hr[t]};hr[t]=en;
    }
    ll ans,dec;
    struct dp{
    	ll v;int c;
    	dp(ll _v=0,ll _c=0):v(_v),c(_c){}
    	dp operator+(const dp o){return dp(v+o.v,c+o.c);}
    	dp operator-(const dp o){return dp(v-o.v,c-o.c);}
    	dp operator*(const dp o){return dp(v+o.v-dec,c+o.c-1);}
    	dp operator+(const ll o){return dp(v+o,c);}
    }f[MN][3];
    dp Max(dp o,dp oo){if(o.v>oo.v)return o;return oo;}
    void dfs(int x,int fa)
    {
    	register int i;
    		
    	for(i=hr[x];i;i=e[i].nex)if(fa^e[i].to)
    	{
    		dfs(e[i].to,x);
    		f[x][2]=Max(f[x][2]+f[e[i].to][0],f[x][1]+f[e[i].to][1]+dp(e[i].w-dec,-1));
    		f[x][1]=Max(f[x][0]+f[e[i].to][1]+e[i].w,f[x][1]+f[e[i].to][0]);
    		f[x][0]=f[x][0]+f[e[i].to][0];
    	}
    	f[x][0]=Max(f[x][0],Max(f[x][1],f[x][2]));
    }
    inline void check(ll mid)
    {
    	register int i;dec=mid;
    	for(i=1;i<=N;++i) f[i][0]=dp(0,0),f[i][2]=f[i][1]=dp(dec,1);
    	dfs(1,0);
    }
    int main()
    {
    	N=read();K=read()+1;
    	register int i,x,y;
    	for(i=1;i<N;++i) x=read(),y=read(),ins(x,y,read());
    	ll l=-inf,r=inf,mid;
    	for(;l<=r;f[1][0].c>=K?r=mid-1:l=mid+1)
    	{
    		mid=(l+r)>>1;check(mid);
    		if(f[1][0].c>=K)ans=f[1][0].v-1ll*f[1][0].c*mid;
    	}
    	return 0*printf("%lld
    ",ans);
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    HDOJ 1202 The calculation of GPA
    HDOJ 1197 Specialized Four-Digit Numbers
    HDOJ 1196 Lowest Bit(二进制相关的简单题)
    HDOJ 1194 Beat the Spread!(简单题)
    NOIP2018游记
    CF1043
    洛谷P1280 尼克的任务
    洛谷P1155 双栈排序
    SPOJ6340 ZUMA
    chessboard
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/lkkts.html
Copyright © 2011-2022 走看看