1 条题解

  • 0
    @ 2025-8-24 23:02:37

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ivyjiao
    复活了

    搬运于2025-08-24 23:02:37,当前版本为作者最后更新于2024-08-25 09:36:12,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    不是,哥们,你真来啊。

    双倍经验:P3320 [SDOI2015] 寻宝游戏

    三倍经验:CF176E Archaeology


    我们先看 P3320。

    结论很好猜,模拟一下走的路径就明白了:

    假设下图中,4,5,84,5,8 号节点有宝物。

    红色路径就是我们来时走过的路径。如果我们算上返回时走的路径,那么我们经过的路径经过且仅经过两次。

    此时根据直觉,能知道这条路径与 LCA 有关,于是我们先敲一个板子。

    void dfs(int u,int fa,int w){
        dep[u]=dep[fa]+1;
        dis[u]=dis[fa]+w;
        f[u][0]=fa;
        for(int i=1;i<=20;i++) f[u][i]=f[f[u][i-1]][i-1];
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i].se,w=G[u][i].fi;
            if(v==fa) continue;
            dfs(v,u,w);
        }
    }
    int lca(int x,int y){
        if(x==y) return x;
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=20;i>=0;i--){
            if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        }
        if(x==y) return x;
        for(int i=20;i>=0;i--){
            if(f[x][i]!=f[y][i]){
                x=f[x][i];
                y=f[y][i];
            }
        }
        return f[x][0];
    }
    int getdis(int x,int y){
        return dis[x]+dis[y]-2*dis[lca(x,y)];
    }
    

    然后进一步分析。我们先假设只有 (4,5)(4,5) 一对点(单程):

    我们发现,结合 LCA,从 4455 的路径长度可以表示为 $dis_4+dis_5-2\times dis_{2}=dis_4+dis_5-2\times dis_{lca_{4,5}}$。

    对于 (5,8)(5,8)(4,8)(4,8) 两对点,也是如此。

    但是我们还发现,如果把宝物点的数量继续增多,那么点对的顺序将不能随意变化。模拟之后,我们发现点对的顺序仅仅和点的 dfs 序有关,且最终 nn 个点组成 nn 个点对,拆开后变成一个环(因为最终要回到最开始的点)。实际上,原图点的顺序就是 dfs 序。

    我们再假设原图中 99 号点也有宝物,那么 44 个点对分别是 (4,5),(5,8),(8,9),(9,4)(4,5),(5,8),(8,9),(9,4)。路径如下(往返):

    distu,v=disu+disv2×dislcau,vdist_{u,v}=dis_u+dis_v-2\times dis_{lca_{u,v}}aia_i 为字典序为第 ii 大的宝物点,则 $ans=dist_{a_1,a_2}+dist_{a_2,a_3}+\cdots+dist_{a_{n-1},a_n}+dist_{a_n,a_1}$。动态维护 ansans 即可。

    dfs 序的顺序是很好维护的,用 set 维护即可,也可以用 rb_tree_tag。

    对于本题,由于我们经过的路径经过且仅经过两次,而本题每条路径只需要算一遍,所以直接将答案 ÷2\div 2 即可。

    代码如下:

    #include<bits/stdc++.h>
    #define PII pair<int,int>
    #define fi first
    #define se second
    #define int long long
    using namespace std;
    int n,m,x,y,z,t,dep[100001],dis[100001],dfn[100001],f[100001][21],sum,ans;
    char op;
    bool vis[100001];
    vector<PII>G[100001];
    set<PII>st;
    void dfs(int u,int fa,int w){
        dep[u]=dep[fa]+1;
        dis[u]=dis[fa]+w;
        dfn[u]=++sum;
        f[u][0]=fa;
        for(int i=1;i<=20;i++) f[u][i]=f[f[u][i-1]][i-1];
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i].se,w=G[u][i].fi;
            if(v==fa) continue;
            dfs(v,u,w);
        }
    }
    int lca(int x,int y){
        if(x==y) return x;
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=20;i>=0;i--){
            if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        }
        if(x==y) return x;
        for(int i=20;i>=0;i--){
            if(f[x][i]!=f[y][i]){
                x=f[x][i];
                y=f[y][i];
            }
        }
        return f[x][0];
    }
    int getdis(int x,int y){
        return dis[x]+dis[y]-2*dis[lca(x,y)];
    }
    signed main(){
        cin>>n;
        for(int i=1;i<n;i++){
            cin>>x>>y>>z;
            G[x].push_back({z,y});
            G[y].push_back({z,x});
        }
        dfs(1,0,0);
        cin>>m;
        while(m--){
            cin>>op;
            if(op=='+'||op=='-'){
                cin>>t;
                vis[t]=!vis[t];
                if(vis[t]) st.insert({dfn[t],t});
                auto it1=st.lower_bound({dfn[t],t}),it2=st.upper_bound({dfn[t],t});
                int a=(it1==st.begin()? (*--st.end()).se:(*--it1).se);
                int b=(it2==st.end()? (*st.begin()).se:(*it2).se);
                swap(a,b);
                if(!vis[t]) st.erase({dfn[t],t});
                int d=getdis(t,a)+getdis(t,b)-getdis(a,b);
                if(vis[t]) ans+=d;
                else ans-=d;
            }
            else cout<<ans/2<<endl;
        }
    }
    
    • 1

    信息

    ID
    10190
    时间
    1000ms
    内存
    512MiB
    难度
    6
    标签
    (无)
    递交数
    0
    已通过
    0
    上传者