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

题面传送门
真是一道大毒瘤题目,写了我两个晚上。
这个题面转化一下就是树上选\(k+1\)条点不相交路径。
首先不难发现有一个\(O(nk)\)的dp:设\(dp_{i,j,0/1/2}\)为\(i\)子树内选了\(j\)条链,当前点度数0/1/2的最大值。随便转移
特别的我们把一个单独的点看作2度数。
然后这个显然是上凸的函数。所以可以WQS二分。
重定义一个pair会比较好写,不过细节仍然很多。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 300000
#define K 100
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (m*x+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
using namespace std;
int n,m,k,x,y,z,siz[N+5];ll l,r,mid;const ll INF=1e16;
struct yyy{int to,w,z;};struct ljb{int head,h[N+5];yyy f[N+5<<1];I void add(int x,int y,int z){f[++head]=(yyy){y,z,h[x]};h[x]=head;}}s;
struct Pai{
	ll w;int g;bool operator >(const Pai &B)const{return w^B.w?w>B.w:g<B.g;}
	Pai operator +(const Pai &B)const{return (Pai){w+B.w,g+B.g};}
	Pai operator +(const int &B)const {return (Pai){w+B,g};}
	Pai operator -(const ll &B)const {return (Pai){w-B,g};}
	Pai operator /(const int &B)const {return (Pai){w,g-1};}
	Pai operator *(const int &B)const {return (Pai){w,g+1};}
}F[N+5][3],Maxn,G[3],Cl=(Pai){-INF,0};
I void dfs(int x,int La){
	RI i;yyy tmp;F[x][0]=(Pai){0,0};F[x][2]=(Pai){-mid,1};for(i=s.h[x];i;i=tmp.z){
		tmp=s.f[i];if(tmp.to==La) continue;dfs(tmp.to,x);memcpy(G,F[x],sizeof(G));F[x][0]=F[x][1]=F[x][2]=Cl;
		Maxn=max(F[tmp.to][0],max(F[tmp.to][1],F[tmp.to][2]));
		F[x][0]=max(F[x][0],G[0]+Maxn);
		F[x][1]=max(F[x][1],max(G[1]+Maxn,G[0]+F[tmp.to][1]+tmp.w));
		F[x][1]=max(F[x][1],(G[0]+F[tmp.to][0]+tmp.w-mid)*1);
		if(G[1].g+F[tmp.to][1].g) F[x][2]=max(F[x][2],(G[1]+F[tmp.to][1]+tmp.w+mid)/1);
		F[x][2]=max(F[x][2],max(G[2]+Maxn,G[1]+F[tmp.to][0]+tmp.w));
	}
}
I int check(){for(RI i=1;i<=n;i++) F[i][0]=F[i][1]=F[i][2]=Cl;dfs(1,0);return /*printf("%lld %d\n",mid,max(max(F[1][0],F[1][1]),F[1][2]).g),*/max(max(F[1][0],F[1][1]),F[1][2]).g>k;}
int main(){
	freopen("1.in","r",stdin);
	RI i;Me(F,-0x3f);scanf("%d%d",&n,&k);k++;for(i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z),s.add(x,y,z),s.add(y,x,z),r+=abs(z);r*=2;l=-r;
	while(l+1<r) mid=l+r>>1,(check()?l:r)=mid;mid=r;check();printf("%lld\n",r*k+max(max(F[1][0],F[1][1]),F[1][2]).w);
}
上一篇:【ybt金牌导航8-5-6】【luogu P1446】卡牌染色 / Cards(Burnside引理)(背包)


下一篇:JAVA第二十一章(小结)