zoukankan      html  css  js  c++  java
  • 【BZOJ5252】【洛谷P4383】【2018九省联考】—林克卡特树(二分+树形dp)

    毒瘤BZOJ1s传送门

    洛谷传送门

    题意有点复杂,实际上就是在求n+1n+1条链,使其长度和最大

    考虑60分的dp
    f[i][j]f[i][j]表示ii的子树有jj条链时的最大长度
    发现这个几乎无法dp对吧

    考虑到链上的点度数必然小于3
    再加一维表示ii的度数

    发现现在就很好维护了
    分类讨论一下就可以了

    但100分时k太大了
    O(nk)O(nk)无法承受

    但如果我们把11~kk时的ff打出来会发现这是一个上凸函数
    就可以带权二分解决了

    不会带权二分可以看这里

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    inline int read(){
    	char ch=getchar();
    	int res=0,f=1;
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
    	return res*f;
    }
    const int N=3e5+5;
    const int infr=1e9;
    const ll inf=1e12;
    int n,k,cnt,adj[N],nxt[N<<1],to[N<<1];
    struct dp{
    	ll val;int k;
    	dp(ll _val=0,int _k=0){
    		val=_val,k=_k;
    	}
    	friend inline bool operator <(const dp &a,const dp &b){
    		return (a.val==b.val)?(a.k>b.k):(a.val<b.val);
    	}
    	friend inline dp operator +(const dp &a,const dp &b){
    		return dp(a.val+b.val,a.k+b.k);
    	}
    }f[N][3],tr[3];
    ll l,r,mid,val[N<<1];
    inline void addedge(int u,int v,int w){
    	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
    }
    inline void init(){
    	for(int i=1;i<=n;i++)f[i][0]=dp(0,0),f[i][1]=dp(-inf,infr),f[i][2]=dp(-mid,1);
    }
    inline void dfs(int u,int fa){
    	for(int e=adj[u];e;e=nxt[e]){
    		int v=to[e];ll va=val[e];
    		if(v==fa)continue;dfs(v,u);
    		for(int i=0;i<3;i++)tr[i]=dp(-inf,infr);
    		for(int i=0;i<3;i++)tr[0]=max(tr[0],f[u][0]+f[v][i]);
    		tr[1]=max(tr[1],f[u][0]+f[v][0]+dp(va-mid,1));
    		tr[1]=max(tr[1],f[u][0]+f[v][1]+dp(va,0));
    		for(int i=0;i<3;i++)tr[1]=max(tr[1],f[u][1]+f[v][i]);
    		tr[2]=max(tr[2],f[u][1]+f[v][0]+dp(va,0));
    		tr[2]=max(tr[2],f[u][1]+f[v][1]+dp(va+mid,-1));
    		for(int i=0;i<3;i++)tr[2]=max(tr[2],f[u][2]+f[v][i]);
    		for(int i=0;i<3;i++)f[u][i]=tr[i];
    	}
    }
    int main(){
    	n=read(),k=read();
    	for(int i=1;i<n;i++){
    		int u=read(),v=read(),w=read();
    		addedge(u,v,w),addedge(v,u,w);
    	}
    	l=-inf,r=inf;
    	while(l<r){
    		mid=(double)(l+r)/2-0.5,init(),dfs(1,0);
    		dp now=max(f[1][0],max(f[1][1],f[1][2]));
    		if(now.k==k+1){cout<<(now.val+(k+1)*mid);return 0;}
    		if(now.k>k+1)l=mid+1;else r=mid;
    	}
    	mid=l,init(),dfs(1,0);dp now=max(f[1][0],max(f[1][1],f[1][2]));
    	cout<<(now.val+(k+1)*mid);
    }
    
    
  • 相关阅读:
    T3054 高精度练习-文件操作 codevs
    0812—①
    T1553 互斥的数 codevs
    T1229 数字游戏 codevs
    T3187 队列练习3 codevs
    Android NDK工程的编译和链接以及使用gdb进行调试
    PE文件附加数据感染之Worm.Win32.Agent.ayd病毒分析
    PE文件加节感染之Win32.Loader.bx.V病毒分析
    Android动态调试so库JNI_Onload函数-----基于IDA实现
    android在JNI_OnLoad入口函数下断点动态调试so库
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145645.html
Copyright © 2011-2022 走看看