先說60分的.
思路題解上很清晰:
問題似乎等價於選k+1條點不相交的鏈哎!我說一下比較坑的地方吧:f(x,k,0/1/2)表示考慮以x為根的子樹,選了k條鏈,點x的度數為0/1/2的最優解.
1.初始化要-inf(反正我不加這個會wa)
2.注意轉移的順序
3.別忘了突然出現新的路徑或者突然消失了乙個路徑的時侯加減1
4.一定要割k下
細節說多不多,說少不少,還得自己打.
說一下100分的.
60分的瓶頸在於k,那麼如果對於k沒有限制的話,那麼我們的轉移就會變成o(n)的(和60分的dp是差不多的).
如何去掉k的限制呢,我們考慮,我們的答案陣列關於下標是凸包(想一下就會發現很顯然啊).那麼我們想到凸包就會想卡他,那麼也就是我們設斜率去卡到k,那麼我們有了斜率會發生什麼呢.
我們的問題轉化為了——設斜率為cost,那麼就是求,這棵樹選取若干條不相交路徑,得到的貢獻是路徑邊權和,代價是每條路徑花費cost,求最終答案(最大化收益),及其路徑條數.
這樣我們每次二分出斜率之後會o(n)出解,得到路徑條數,從而繼續二分.
不難打,有了60分的dp之後,給到二分斜率的思路就應該可以寫出來了.
(補充一下:這玩意似乎是wqs二分……)
#include #includekod#include
char xb[(1
<<15)+10],*xs,*xt;
#define gtc() (xs==xt&&(xt=(xs=xb)+fread(xb,1,1<<15,stdin),xs==xt)?0:*xs++)inline
void read(int &x)
typedef
long
long
ll;const
int n=300010
;const ll inf=1e15;
struct
vc[n
<<1
];int
head[n],t;
inline
void add(int x,int y,int
z)int
n;ll k;
struct
a inline
void
set()
inline a up()
inline
void
cover(a a)
inline
void
cover(a a,a b)
inline
void cover(a a,a b,ll w,int
opt)
}f[n][3];
inline
void dfs(int x,int
fa) f[x][
1].cover(f[x][0
].up());
f[x][
2].cover(f[x][1
]); f[x][
2].cover(f[x][0
]);}
inline a solve()
intmain()
ll l=-1e12,r=1e12,mid,ans=0
; a ret;
while(l<=r)
printf(
"%lld\n
",ans);
return0;
}
HEOI 2018 Day2 T2 林克卡特樹
給乙個n個節點的樹,然後將其分成k 1個聯通塊,再在每個聯通塊取一條路徑,將其連線起來,求連線起來的路徑最大權值。考場只會20分,還都打掛了 60分的做法其實並不難,nk dp即可,設 f i,j,0 1 2 表示i子樹選取了j個聯通塊,i這個節點連了0 1 2條邊時的最優解。100分的做法就是60...
2018八省聯考 林克卡特樹
題目真滴皮 orz rqy 10分的暴力都沒拿到 10分直接求直徑 60分 容易?想到題目等價於求k 1條不相交的鏈 設狀態f i j 0 1 2 f i j 0 1 2 表示以第i個節點為根的子樹用了j條鏈並且根和兒子連有 0,1,2 條邊。轉移分為5類 g j cc 0 max g j cc 0...
八省聯考2018 林克卡特樹
挺簡單的一道題。原題斷k kk條邊連k kk條邊權為0 00的邊相當於尋去k 1 k 1k 1條不相交鏈出來,將它們連上得到的結果。所以我們要從原樹中選取k 1 k 1k 1條鏈出來,使得它們的權值和最大。我們發現恰好k 1 k 1k 1條鏈這個限制是比較難限制的,考慮通過凸優化二分去進行維護。由於...