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;
}
posted @ 2023-07-09 21:17  蒟蒻·廖子阳  阅读(23)  评论(0编辑  收藏  举报