题面传送门
真是一道大毒瘤题目,写了我两个晚上。
这个题面转化一下就是树上选\(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); }