P3320 [SDOI2015] 寻宝游戏

P3320 [SDOI2015] 寻宝游戏

题目描述

小 B 最近正在玩一个寻宝游戏,这个游戏的地图中有 \(N\) 个村庄和 \(N-1\) 条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。

小 B 希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小 B 需要不断地更新数据,但是小 B 太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物。

输入格式

第一行,两个整数 \(N,M\),其中 \(M\) 为宝物的变动次数。

接下来的 \(N-1\) 行,每行三个整数 \(x,y,z\),表示村庄 \(x,y\) 之间有一条长度为 \(z\) 的道路。

接下来的 \(M\) 行,每行一个整数 \(t\),表示一个宝物变动的操作。若该操作前村庄 \(t\) 内没有宝物,则操作后村庄内有宝物;若该操作前村庄 \(t\) 内有宝物,则操作后村庄内没有宝物。

输出格式

\(M\) 行,每行一个整数,其中第 \(i\) 行的整数表示第 \(i\) 次操作之后玩家找到所有宝物需要行走的最短路程。若只有一个村庄内有宝物,或者所有村庄内都没有宝物,则输出 0

提示

  • 对于 \(100\%\) 的数据,\(1 \leq N \leq 100000,\ 1 \leq M \leq 100000,\ 1 \leq z \leq 10^9\)

Solution:

妙妙树上结论题,我们对一颗树求 \(dfn\) ,然后我们维护一个当前所有关键点的序列

那么对于每次修改,我们找到序列上与 \(pos\) 相邻的两个点 \(l,r\) 假设我们要插入\(pos\) 那么产生的贡献将是
\(dis_{l,pos}+dis_{pos,r}-dis_{l,r}\)

删除取相反数就好了

然后维护序列的方法有很多,反正我选了抽象 set (vector用太多了)

Code:

#include<bits/stdc++.h>
#define int long long
const int N=1e5+5;
const int lg=17;
using namespace std;
vector<tuple<int,int> >E[N];
set<int> st;
set<int>::iterator it;
int n,m,ans;
int a[N];
int f[N][lg+5],dfn[N],rid[N],dis[N],dep[N];
int col[N];
void dfs(int x,int fa)
{
    dfn[x]=++dfn[0];rid[dfn[0]]=x;dep[x]=dep[fa]+1;
    f[x][0]=fa;
    for(int j=1;j<=lg;j++)f[x][j]=f[f[x][j-1]][j-1];
    for(auto [y,w] : E[x]){if(y==fa)continue;dis[y]=dis[x]+w;dfs(y,x);}
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int j=lg;j>=0;j--)if(dep[f[x][j]]>=dep[y])x=f[x][j];
    if(x==y)return x;
    for(int j=lg;j>=0;j--)if(f[x][j]!=f[y][j])x=f[x][j],y=f[y][j];
    return f[x][0];
}
int Dis(int x,int y)
{
    int lca=LCA(x,y);
    return dis[x]+dis[y]-dis[lca]*2;
}
void work()
{
    cin>>n>>m;
    for(int i=1,x,y,w;i<n;i++)
    {
        scanf("%lld%lld%lld",&x,&y,&w);
        E[x].emplace_back(y,w);
        E[y].emplace_back(x,w);
    }
    dfs(1,0);
    for(int i=1,x,y,z;i<=m;i++)
    {
        scanf("%lld",&x);
        col[x]^=1;
        if(col[x])st.insert(dfn[x]);
        y=rid[(it=st.lower_bound(dfn[x]))==st.begin() ? *--st.end() : *--it];
        z=rid[(it=st.upper_bound(dfn[x]))==st.end() ? *st.begin() : *it];
        if(!col[x])st.erase(dfn[x]);
        int d=Dis(x,y)+Dis(x,z)-Dis(y,z);
        ans+= col[x]==1 ? d : -d;
        printf("%lld\n",ans);
    }
}
#undef int
int main()
{
    //freopen("P3320.in","r",stdin);freopen("P3320.out","w",stdout);
    work();
    return 0;
}
posted @ 2024-12-25 21:45  liuboom  阅读(30)  评论(0)    收藏  举报