题解 CF1016F【Road Projects】

$\text{Link}$

题意

给一颗 $n$ 个结点的带权树,$q$ 组询问在树上加一条长度为 $x$ 的边后 $1\to n$ 的最短路的最大值。

$n,q\le 3\times 10^5$.

思路

锐评:看不懂某篇单调栈,于是来写个前缀和。

照样把 $1\to n$ 的链拉出来并标记它们,令它们的 $v_i=1$,链长为 $t$。

令 $p_i$ 表示被标记的点 $i$ 到 $1$ 的权值和,$d_i$ 表示被标记的点 $i$ 到它不被标记的儿子的子树中最大的距离,$s_i$ 表示点 $i$ 不被标记的儿子的子树中的点数和。

首先答案不大于 $p_n$。考虑 $\exists v_i=1,s_i\ge 2$,则连接它的链外子树中任意两点,不改变最短路,答案为 $p_n$。

否则,考虑在 $i$ 或它的的链外子树和 $j$ 或它的的链外子树中选两个点连边,答案为$$\max_{i<j,v_{i,j}=1}(p_i+d_i-p_j+d_j+p_n+x)$$

可以发现,答案只与前四项有关,处理出 $p_i+d_i$ 的前缀 $\max pr_i$ 和取到的位置 $prp_i$,处理出 $-p_i+d_i$ 的后缀 $\max sf_i$ 和取到的位置 $sfp_i$,答案则为$$\max_{i=1}^{t-1} (pr_i+sf_{i+1})+p_n+x$$

特别地,当最优决策相邻并且都没有链外子树时不能取到。

做完了,时间复杂度 $\Theta(n+q)$。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int N=3e5+10;
struct Edge{
    int to,nxt,w;
}a[N<<1];
int n,q,siz[N],fa[N],cnt,head[N];
ll p[N],d[N];
bool vis[N];
vector<int>vec;
inline void add(int u,int v,int w){
    cnt++;
    a[cnt].to=v;
    a[cnt].nxt=head[u];
    a[cnt].w=w;
    head[u]=cnt;
}
inline void dfs1(int rt,int f){
    fa[rt]=f;
    for(int i=head[rt];i;i=a[i].nxt){
        int t=a[i].to;
        if(t==f) continue;
        dfs1(t,rt);
    }
}
inline void dfs2(int rt){
    siz[rt]=1;
    if(vis[rt]) vec.push_back(rt);
    for(int i=head[rt];i;i=a[i].nxt){
        int t=a[i].to;
        if(t==fa[rt]) continue;
        if(vis[t])
            p[t]=p[rt]+a[i].w;
        dfs2(t);
        if(!vis[t])
            siz[rt]+=siz[t],
            d[rt]=max(d[rt],d[t]+a[i].w);
    }
}
bool fl;
int prp[N],sup[N];
ll pr[N],sf[N],sep[N],ses[N],ans=-2e18;
int main(){
    n=read(),q=read();
    for(int i=1;i<n;i++){
        int u=read(),v=read(),w=read();
        add(u,v,w),add(v,u,w);
    }
    dfs1(1,0);
    for(int i=n;i;i=fa[i])
        vis[i]=1;
    vec.push_back(0);
    dfs2(1);
    for(int i=1;i<=n;i++)
        if(siz[i]>=3) 
            fl=1;
    pr[0]=sf[vec.size()]=-2e18;
    for(int i=1;i<vec.size();i++){
        ll tmp=p[vec[i]]+d[vec[i]];
        if(tmp>pr[i-1]) pr[i]=tmp,prp[i]=i;
        else pr[i]=pr[i-1],prp[i]=prp[i-1];
    }
    for(int i=vec.size()-1;i;i--){
        ll tmp=-p[vec[i]]+d[vec[i]];
        if(tmp>sf[i+1]) sf[i]=tmp,sup[i]=i;
        else sf[i]=sf[i+1],sup[i]=sup[i+1];
    }
    for(int i=1;i<vec.size();i++){
        if(prp[i-1]==i-1&&sup[i]==i&&siz[vec[i-1]]==1&&siz[vec[i]]==1) continue;
        ans=max(ans,pr[i-1]+sf[i]);
    }
    ans+=p[n];
    for(int i=1;i<vec.size()-2;i++)
        ans=max(ans,p[vec[i]]+p[n]-p[vec[i+2]]);
    for(int i=1;i<vec.size();i++){
        if(siz[vec[i]]==1) continue;
        if(i!=1) ans=max(ans,p[vec[i-1]]+d[vec[i]]+p[n]-p[vec[i]]);
        if(i!=vec.size()-1) ans=max(ans,p[vec[i]]+d[vec[i]]+p[n]-p[vec[i+1]]);
    }
    while(q--){
        int x=read();
        write(fl?p[n]:min(ans+x<=0?p[n]:ans+x,p[n])),putc('\n');
    }
    flush();
}

再见 qwq~

posted @ 2022-02-15 19:49  ffffyc  阅读(8)  评论(0)    收藏  举报  来源