bzoj5252 [2018多省省队联测]林克卡特树
生活随笔
收集整理的這篇文章主要介紹了
bzoj5252 [2018多省省队联测]林克卡特树
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
斜率優(yōu)化樹形dp??
我們先將問題轉(zhuǎn)化成在樹上選K+1條互不相交路徑,使其權(quán)值和最大。
然后我們考慮60分的dp,直接維護(hù)每個(gè)點(diǎn)子樹內(nèi)選了幾條路徑,然后該點(diǎn)和0/1/2條路徑相連
然后我們會(huì)發(fā)現(xiàn)最后的答案關(guān)于割的邊數(shù)是一個(gè)單峰的函數(shù),這時(shí)候事情就變得明朗起來個(gè)p
我們考慮拿一條斜率為k的直線去切這個(gè)函數(shù),切到的點(diǎn)是什么?是每選一條路徑額外付出k點(diǎn)代價(jià)時(shí)的最優(yōu)解,于是我們二分這個(gè)斜率,然后直接樹形dp求最優(yōu)解以及位置即可,因?yàn)槊看蔚淖顑?yōu)解一定是上次的最優(yōu)解和兒子的最優(yōu)解共同轉(zhuǎn)移而來的,所以我們只需要對(duì)每個(gè)度數(shù)維護(hù)最優(yōu)解和位置即可。然后我們就可以根據(jù)dp出的位置調(diào)整斜率,然后找到答案。
這不就是wqs二分嗎。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #define N 300500 7 #define pr pair<long long,int> 8 #define mk make_pair 9 #define fir first 10 #define sec second 11 #define inf 0x7fffffffffffffff 12 using namespace std; 13 int e=1,head[N]; 14 struct edge{ 15 int v,w,next; 16 }ed[N<<1]; 17 void add(int u,int v,int w){ 18 ed[e].v=v;ed[e].w=w; 19 ed[e].next=head[u];head[u]=e++; 20 } 21 int n,m,K; 22 long long ans; 23 pr f[N][3],g[3],mx; 24 void add(pr &a,pr b){if(b.fir>a.fir||(b.fir==a.fir&&b.sec<a.sec))a=b;} 25 void dfs(int x,int fa){ 26 f[x][0]=mk(0,0);f[x][1]=mk(-m,1);f[x][2]=mk(-inf,0); 27 for(int i=head[x];i;i=ed[i].next){ 28 int v=ed[i].v; 29 if(v==fa)continue; 30 dfs(v,x); 31 g[0]=f[x][0];g[1]=f[x][1];g[2]=f[x][2]; 32 mx=f[v][0];add(mx,f[v][1]);add(mx,f[v][2]); 33 add(f[x][0],mk(g[0].fir+mx.fir,g[0].sec+mx.sec)); 34 add(f[x][1],mk(g[1].fir+mx.fir,g[1].sec+mx.sec)); 35 add(f[x][1],mk(g[0].fir+f[v][1].fir+ed[i].w,g[0].sec+f[v][1].sec)); 36 add(f[x][2],mk(g[2].fir+mx.fir,g[2].sec+mx.sec)); 37 add(f[x][2],mk(g[1].fir+f[v][1].fir+ed[i].w+m,g[1].sec+f[v][1].sec-1)); 38 } 39 } 40 int main(){ 41 scanf("%d%d",&n,&K); 42 for(int i=1,u,v,w;i<n;i++){ 43 scanf("%d%d%d",&u,&v,&w); 44 add(u,v,w);add(v,u,w); 45 } 46 int l=-1000000000,r=1000000000,mid,fin; 47 while(l<=r){ 48 m=mid=(l+r)>>1; 49 dfs(1,0); 50 mx=f[1][0];add(mx,f[1][1]);add(mx,f[1][2]); 51 if(mx.sec<=K+1)fin=mid,r=mid-1; 52 else l=mid+1; 53 } 54 m=fin; 55 dfs(1,0); 56 mx=f[1][0];add(mx,f[1][1]);add(mx,f[1][2]); 57 ans=mx.fir+1ll*(K+1)*m; 58 printf("%lld\n",ans); 59 return 0; 60 } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/Ren-Ivan/p/8782360.html
總結(jié)
以上是生活随笔為你收集整理的bzoj5252 [2018多省省队联测]林克卡特树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么我们需要Maven
- 下一篇: Tomcat NIO