SP1825 FTOUR2 - Free tour II
给出 \(n\) 个点的树,有 \(m\) 个黑点,边有权值。求出黑点个数 \(\le k\) 的路径的最大边权和。
\(n\le 2\times 10^5\)。
点分治模板题,令当前分治重心为 \(rt\),预处理每个点到 \(rt\) 的黑点数(不含 \(rt\))\(num_u\) 和边权和 \(val_u\)。设 \(black_u=0/1\) 表示点 \(u\) 不是/是黑点,对于一个点 \(u\),统计之前子树 \(\max\limits_{num_v\le k-num_u-black_{rt}}\{val_v\}\),记为 \(maxv\),给答案贡献 \(maxv+val_u\)。树状数组维护之。由于值域涉及到 \(0\),因此所有插入操作位置 \(+1\),对应删除/查询也 \(+1\)。
时间复杂度 \(\mathcal{O}(n\cdot \log n\cdot \log m)\),空间复杂度 \(\mathcal{O}(n)\)。
$\bf\color{orange}代码$
#include<bits/stdc++.h>
#define ll long long//防祖宗。
#define lb(x) ((x)&(-x))
using namespace std;
const int N=2e5+5,inf=1e18;
int n,m,k,rt,mx[N],tot,sz[N],num[N],a[N],cnt,top,stk[N];
ll bit[N],val[N],ans;//ans 初始化为 0 表示选单点。大抵是有解的。
bool black[N],vis[N];
vector<pair<int,ll>>g[N];
void read(int&x){//快读。
x=0;
int w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
w=-1;
}
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
x*=w;
}
void write(ll x){
if(x>9){
write(x/10);
}
putchar(x%10+48);
}
void gravity(int u,int fa){
sz[u]=1;
mx[u]=0;
for(auto[v,w]:g[u]){
if((v^fa)&&!vis[v]){
gravity(v,u);
sz[u]+=sz[v];
mx[u]=max(mx[u],sz[v]);
}
}
mx[u]=max(tot-sz[u],mx[u]);
if(mx[u]<mx[rt]){
rt=u;
}
}
void get(int u,int fa){
a[++cnt]=u;
for(auto[v,w]:g[u]){
if((v^fa)&&!vis[v]){
num[v]=num[u]+black[v];
val[v]=val[u]+w;
get(v,u);
}
}
}
void modify(int x,ll k){
for(int i=x;i<=m+1;i+=lb(i)){
bit[i]=max(bit[i],k);
}
}
ll query(int x){
ll res=-inf;
for(int i=x;i;i-=lb(i)){
res=max(res,bit[i]);
}
return res;
}
void clear(int x){
for(int i=x;i<=m+1;i+=lb(i)){
bit[i]=-inf;
}
}
void divide(int u){
vis[u]=1;
for(auto[v,w]:g[u]){
if(!vis[v]){
cnt=0;
num[v]=black[v];
val[v]=w;
get(v,u);
for(int i=1;i<=cnt;++i){
if(num[a[i]]<=k-black[u]){
ans=max(ans,val[a[i]]+query(k-black[u]-num[a[i]]+1));
}
}
for(int i=1;i<=cnt;++i){
if(num[a[i]]<=k-black[u]){
modify(num[a[i]]+1,val[a[i]]);
stk[++top]=num[a[i]]+1;
}
}
}
}
ans=max(ans,query(k-black[u]+1));
while(top){
clear(stk[top--]);
}
for(auto[v,w]:g[u]){
if(!vis[v]){
tot=sz[v];
mx[rt=0]=1e9;
gravity(v,0);
gravity(rt,0);
divide(rt);
}
}
}
signed main(){
read(n);
read(k);
read(m);
for(int x,i=1;i<=m;++i){
read(x);
black[x]=1;
}
for(int i=1,u,v,w;i^n;++i){
read(u);
read(v);
read(w);
g[u].emplace_back(v,w);
g[v].emplace_back(u,w);
}
tot=n;
mx[0]=1e9;
gravity(1,0);
gravity(rt,0);
for(int i=1;i<=m+1;++i){
bit[i]=-inf;
}
divide(rt);
write(ans);
return 0;
}