zoukankan      html  css  js  c++  java
  • P4383 [八省联考2018]林克卡特树 树形dp Wqs二分

    LINK:林克卡特树

    作为树形dp 这道题已经属于不容易的级别了。

    套上了Wqs二分 (反而更简单了 大雾

    容易想到还是对树进行联通情况的dp 然后最后结果总和为各个联通块内的直径.

    (f_{i,j})表示以i为根的子树内有j条边被删掉 可以发现这个状态难以转移。

    需要换个状态 一个比较经典的做法是套用树的直径的那套来做 每个点向上传递单条链或者什么都不传来转移。

    传递单条链可以在父亲的那个地方合成一条 然后钦定此条为以x为根的联通内的最大值 那么就可以从x所在父亲的那条边切断了。

    或者 传递到父亲那里 再向上传单条链。

    传双条链可以默认直接断开 相当于什么都不传。

    这样各个联通块都容易dp出来代价了。

    但x处还需要开一个状态表示以x在链上且不想上传递链的最大值。

    那么只有三种 可以形象的描述为x的度数为0,1,2.

    即设(f_{i,j,0/1,2})分别表示此时断开k条链时分别为上述三个状态的最大值。

    转移很容易 不再赘述 值得一提的是转移结束时 对于(f_{x,1},f_{x,2})都需要再向(f_{x,0})进行过渡转移。

    这是(ncdot k^2)的。

    恰好分k个容易想到 Wqs二分 二分斜率切凸包即可。

    复杂度(ncdot log Mx)

    code
    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 10000000000000000ll
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-6
    #define sq sqrt
    #define S second
    #define F first
    #define mod 1000000007
    #define V vector
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=300010;
    int n,len,k;
    int fa[MAXN];
    int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],e[MAXN<<1];
    ll l,r,mid;
    struct wy
    {
    	ll s;int v;
    	inline wy friend operator +(wy a,wy b){return (wy){a.s+b.s,a.v+b.v};}
    	inline bool friend operator <(wy a,wy b){return a.s<b.s||(a.s==b.s&&a.v<b.v);}	
    }f[MAXN][3];
    inline wy max(wy a,wy b){return a<b?b:a;}
    inline void add(int x,int y,int z)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    	e[len]=z;
    }
    inline void dfs(int x,int father)
    {
    	fa[x]=father;
    	go(x)if(tn!=father)dfs(tn,x);
    }
    inline void dp(int x)
    {
    	f[x][0]=(wy){0,0};f[x][1]=(wy){0,0};f[x][2]=(wy){mid,1};
    	go(x)if(tn!=fa[x])
    	{
    		dp(tn);
    		f[x][2]=max(f[x][2]+f[tn][0],f[x][1]+f[tn][1]+(wy){mid+e[i],1});
    		f[x][1]=max(f[x][1]+f[tn][0],f[x][0]+f[tn][1]+(wy){e[i],0});
    		f[x][0]=f[x][0]+f[tn][0];
    	}
    	f[x][0]=max(f[x][0],max(f[x][1]+(wy){mid,1},f[x][2]));
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(n);get(k)+1;
    	rep(2,n,i)
    	{
    		int get(x),get(y),get(z);
    		add(x,y,z);add(y,x,z);
    		r+=z>0?z:-z;
    	}
    	dfs(1,0);l=-r;
    	while(l<r)
    	{
    		mid=(l+r)>>1;
    		dp(1);
    		if(f[1][0].v>=k)r=mid;
    		else l=mid+1;
    	}
    	mid=r;dp(1);
    	printf("%lld
    ",f[1][0].s-mid*k);
    	return 0;
    }
    
  • 相关阅读:
    react特点和创建虚拟DOM
    vue的keep-alive
    JavaScript-事件委托
    vue-router参数传递
    js常用的字符串处理
    vue-vuex
    vue-组件
    vue-父子组件传值
    堆和栈
    js-深拷贝浅拷贝
  • 原文地址:https://www.cnblogs.com/chdy/p/13301738.html
Copyright © 2011-2022 走看看