LuoguP4383 [八省聯考2018]林克卡特樹lct
阿新 • • 發佈:2018-12-02
tmp problem name ace typename 路徑 選擇 出現 由於
LuoguP4383 [八省聯考2018]林克卡特樹lct
https://www.luogu.org/problemnew/show/P4383
分析:
- 題意等價於選擇\(K\)條點不相交的鏈,使得總路徑長度和最大。
- 設\(f[x][i][0/1/2]\)表示\(x\)子樹中選了\(i\)個,\(x\)的當前度數為\(0/1/2\)的答案。
- 然後我們感性理解一下可知,選\(k\)個點的方案,一定能夠從\(k-1\)個點的方案中轉移過來的,不會出現從\(k-i(i>1)\)上再選若幹個不在\(k-1\)的方案中的鏈轉移過來答案更優。
- 那麽由於我們選擇的鏈的權值是不斷變小的,可知\(dp\)值是個凸函數,且單峰。
- 使用帶權二分即可,對於本題,整數二分就可以通過。
代碼:
// luogu-judger-enable-o2 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 300050 typedef long long ll; const ll inf = 1ll<<60; int head[N],to[N<<1],nxt[N<<1],cnt,val[N<<1],n,K,siz[N]; // ll f[N][105][3],tmp[105][3]; struct A { ll x; int k; A() {} A(ll x_,int k_) {x=x_, k=k_;} bool operator < (const A &u) const { return x==u.x ? k>u.k : x<u.x; } A operator + (const A &u) const { return A(x+u.x, k+u.k); } }f[N][3],ans,tmp[3]; inline void add(int u,int v,int w) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w; } template<typename T>void chkmax(T &x,T y) {if(x<y)x=y;} template<typename T>void chkmin(T &x,T y) {if(y<x)x=y;} ll C; // void dfs(int x,int y) { // int i,j,k,p,q; siz[x]=1; // memset(f[x],0xc0,sizeof(f[x])); // f[x][0][0]=f[x][1][2]=0; // for(i=head[x];i;i=nxt[i]) if(to[i]!=y) { // dfs(to[i],x); // for(j=0;j<=K&&j<=siz[x];j++) for(k=0;k<3;k++) tmp[j][k]=f[x][j][k], f[x][j][k]=-inf; // int t=to[i],len=val[i]; // for(j=0;j<=K&&j<=siz[x];j++) { // for(k=0;k<=K-j+1&&k<=siz[to[i]];k++) { // //not choose // for(p=0;p<3;p++) for(q=0;q<3;q++) chkmax(f[x][j+k][p],tmp[j][p]+f[t][k][q]); // //choose // chkmax(f[x][j+k+1][1],tmp[j][0]+f[t][k][0]+len); // chkmax(f[x][j+k][1],tmp[j][0]+f[t][k][1]+len); // chkmax(f[x][j+k][2],tmp[j][1]+f[t][k][0]+len); // chkmax(f[x][j+k-1][2],tmp[j][1]+f[t][k][1]+len); // } // } // siz[x]+=siz[to[i]]; // } // } void dfs(int x,int y) { int i,p,q; f[x][0]=A(0,0); f[x][1]=A(-inf,0); f[x][2]=A(C,1); for(i=head[x];i;i=nxt[i]) if(to[i]!=y) { int t=to[i]; dfs(to[i],x); memcpy(tmp,f[x],sizeof(f[x])); f[x][0]=f[x][1]=f[x][2]=A(-inf,0); //not choose for(p=0;p<3;p++) for(q=0;q<3;q++) chkmax(f[x][p],tmp[p]+f[t][q]); chkmax(f[x][1],tmp[0]+f[t][0]+A(val[i]+C,1)); chkmax(f[x][1],tmp[0]+f[t][1]+A(val[i],0)); chkmax(f[x][2],tmp[1]+f[t][0]+A(val[i],0)); chkmax(f[x][2],tmp[1]+f[t][1]+A(val[i]-C,-1)); } } int main() { scanf("%d%d",&n,&K); K++; int i,x,y,z; for(i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } // dfs(1,0); // printf("%lld\n",max(max(f[1][K][0],f[1][K][1]),f[1][K][2])); ll l=-1e9, r=1e9; while(l<r) { ll mid=(l+r)>>1; C=mid; dfs(1,0); ans=max(max(f[1][0],f[1][1]),f[1][2]); if(ans.k>K) r=mid; else if(ans.k==K) { printf("%lld\n",ans.x-K*C); return 0; } else l=mid+1; } l--; C=l; dfs(1,0); ans=max(max(f[1][0],f[1][1]),f[1][2]); printf("%lld\n",ans.x-K*C); }
LuoguP4383 [八省聯考2018]林克卡特樹lct