zoukankan      html  css  js  c++  java
  • [BZOJ5252][八省联考2018]林克卡特树lct

    bzoj(上面可以下数据)
    luogu

    description

    在树上选出(k)条点不相交的链,求最大权值。
    一个点也算是一条退化的链,其权值为(0)

    sol

    别问我为什么现在才写这题
    首先可以有一个很显然的(O(nk))(dp)
    (f_{i,j,0/1/2})表示(i)为根的子树中选出了(j)条链,此时(i)点的度数为(0/1/2)的最大权值。
    然后你会发现这种选(k)个东西最大化收益/最小化代价的函数都会是凸的。
    然后就凸优化一下?
    然后就做完啦?

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    #define ll long long
    const int N = 3e5+5;
    const ll inf = 1ll<<60;
    struct info{
    	ll f;int k;
    	bool operator < (const info &b) const
    		{return f==b.f?k>b.k:f<b.f;}
    	info operator + (const info &b) const
    		{return (info){f+b.f,k+b.k};}
    }dp[N][3],ans;
    int n,k,to[N<<1],nxt[N<<1],ww[N<<1],head[N],cnt;
    void link(int u,int v,int w){
    	to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;head[u]=cnt;
    }
    inline void upt(info &x,info y){if(x<y)x=y;}
    void dfs(int u,int f,ll c){
    	dp[u][0]=(info){0,0};dp[u][1]=(info){-c,1};dp[u][2]=(info){-inf,0};
    	for (int e=head[u];e;e=nxt[e])
    		if (to[e]!=f){
    			int v=to[e];dfs(v,u,c);
    			info tmp=max(dp[v][0],max(dp[v][1],dp[v][2]));
    			upt(dp[u][2],dp[u][2]+tmp);
    			upt(dp[u][2],dp[u][1]+dp[v][1]+(info){ww[e]+c,-1});
    			upt(dp[u][1],dp[u][1]+tmp);
    			upt(dp[u][1],dp[u][0]+dp[v][1]+(info){ww[e],0});
    			upt(dp[u][1],dp[u][0]+dp[v][0]+(info){-c,1});
    			upt(dp[u][0],dp[u][0]+tmp);
    		}
    }
    void solve(ll c){
    	dfs(1,0,c);ans=(info){-inf,0};
    	for (int i=1;i<=n;++i)
    		upt(ans,max(dp[i][0],max(dp[i][1],dp[i][2])));
    }
    int main(){
    	n=gi();k=gi()+1;ll L=0,R=0;
    	for (int i=1;i<n;++i){
    		int u=gi(),v=gi(),w=gi();
    		link(u,v,w);link(v,u,w);
    		L-=abs(w);R+=abs(w);
    	}
    	while (L<R){
    		ll mid=(L+R)>>1;solve(mid);
    		if (ans.k<=k) R=mid;else L=mid+1;
    	}
    	solve(R);printf("%lld
    ",ans.f+R*k);
    	return 0;
    }
    
  • 相关阅读:
    安卓中像素px和dp的转换
    Android 使用Vector XML文件创建矢量图片资源,editText监听
    动态设置RecyclerView的高度
    EditText一些用法
    各种加密算法比较
    多线程--Task,等待用户输入AutoResetEvent
    AutoCAD二次开发——AutoCAD.NET API开发环境搭建
    Office(Excel、Word)二次开发——VSTO
    个人信息管理PIM——密码管理工具软件
    【矩阵计算】矩阵乘法其一:基础符号和算法
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9428786.html
Copyright © 2011-2022 走看看