P4383 [八省联考 2018] 林克卡特树 题解
题意
给你一棵 \(n\) 个点的树 \(T\),边有正负权值,要求切断原树 \(T\) 中的 \(k\) 条边,然后新添加 \(k\) 条权值为 0 的边使其成为一棵新树 \(T'\),求树 \(T'\) 的直径最大是多少。
题意转化
我们发现切割的操作将树 \(T\) 分为了 \(k+1\) 个连通块,而连边操作则可以帮我们将在原树 \(T\) 上不交的链连接在一起,于是题目就变成了求树 \(T\) 上 \(k+1\) 条不交链的最大权值和。
Solution1
我们先考虑最朴素的树形 dp,记 \(f_{i,j,k}\) 表示在节点 \(i\) 时有 \(j\) 条链,且节点 \(i\) 在自己所在链中的度数为 \(k\),显然 \(k=0,1,2\)。接下来考虑以 \(x\) 为根的子树到 \(i\) 的转移,记 \(i\) 与 \(x\) 之间的边权为 \(w\):
- 我们发现,\(\forall k=1,2,3\) 都可以直接继承子树中的链,即:\[t=\max(f_{x,y,0},f_{x,y,1},f_{x,y,2}) \]\[f_{i,j,k}=\max(f_{i,j,k},f_{i,j-y,k}+t) \]
- 继续考虑 \(k=1\) 时的转移,发现 \(i\) 的这条链可以是 \(i\) 与 \(x\) 之间的链,也可以是 \(i\) 与 \(x\) 在 \(k=1\) 时的链连接在一起,即:
\[f_{i,j,1}=\max(f_{i,j,1},f_{i,j-y,0}+w+\max(f_{x,y-1,0},f_{x,y,1}))
\]
- 最后考虑 \(k=2\) 时的转移,发现 \(i\) 的这条链可以是 \(i\) 在 \(k=1\) 时的链与 \(i\) 和 \(x\) 之间的链组合而成,也可以是 \(i\) 在 \(k=1\) 时的链与 \(x\) 在 \(k=1\) 时的链连接在一起,即:
\[f_{i,j,2}=\max(f_{i,j,2},f_{i,j-y,1}+w+\max(f_{x,y,0},f_{x,y+1,1}))
\]
我们发现虽然是按照 \(k\) 从小到大讨论的转移,但是 \(f\) 在 \(k\) 更大时的转移需要用到 \(f\) 在 \(k\) 更小时的值,所以应该按 \(k\) 从大到小转移,或者用临时变量存下来,这个算法的时间复杂度是 \(O(nk^2)\)。
Solution2
考虑优化上面的算法,链不交而且要求权值最大启发我们使用 wqs 二分,你感性理解,发现我们应该会先选长的不交链再选短的不交链,即 \(f\) 是关于 \(k\) 上凸的,所以 wqs 二分可以优化掉 \(k\) 的限制,使得单次 \(dp\) 的时间复杂度为 \(O(n)\),具体实现与 Solution1 基本类似,就不加以赘述,最后该算法时间复杂度应该是 \(O(n\log V)\),\(V\) 大约是 \(10^{12}\) 级别的。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf=1e12;
int n,k;
vector<pair<int,int>> e[300005];
struct node{
int val,k;
}f[300005][3],tr[3];
node operator+(node x,node y){return node{x.val+y.val,x.k+y.k};}
bool operator<(node x,node y){return ((x.val<y.val||(x.val==y.val&&x.k>y.k)));}
template<typename T> inline T maxk(T x,T y){return (x<y)?y:x;}
template<typename T,typename ...T1> inline T maxk(T x,T y,T1...z){return (x<y)?maxk(y,z...):maxk(x,z...);}
void dfs(int x,int fa,int c){
f[x][0]={0,0},f[x][1]={-inf,inf},f[x][2]={-c,1};
for(auto [i,j]:e[x])if(i!=fa){
dfs(i,x,c);
tr[0]=tr[1]=tr[2]={-inf,inf};
auto t=maxk(f[i][0],f[i][1],f[i][2]);
tr[0]=maxk(tr[0],f[x][0]+t);
tr[1]=maxk(tr[1],f[x][1]+t);
tr[2]=maxk(tr[2],f[x][2]+t);
tr[1]=maxk(tr[1],f[x][0]+f[i][0]+node{j-c,1});
tr[1]=maxk(tr[1],f[x][0]+f[i][1]+node{j,0});
tr[2]=maxk(tr[2],f[x][1]+f[i][0]+node{j,0});
tr[2]=maxk(tr[2],f[x][1]+f[i][1]+node{j+c,-1});
f[x][0]=tr[0],f[x][1]=tr[1],f[x][2]=tr[2];
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>k;
for(int i=1;i<n;i++){
int x,y,z;
cin>>x>>y>>z;
e[x].push_back(make_pair(y,z));
e[y].push_back(make_pair(x,z));
}
int l=-1e12,r=1e12;
while(l<=r){
int mid=(l+r)>>1;
dfs(1,1,mid);
auto [x,y]=maxk(f[1][0],f[1][1],f[1][2]);
if(y==k+1){cout<<(k+1)*mid+x;return 0;}
if(y>k+1)l=mid+1;else r=mid-1;
}
dfs(1,1,l);
auto [x,y]=maxk(f[1][0],f[1][1],f[1][2]);
cout<<(k+1)*l+x;
return 0;
}

浙公网安备 33010602011771号