P3320 [SDOI2015]寻宝游戏(set+LCA)

题目传送门

题意

一棵 n 个节点的树,边有边权。
每个点可能是关键点,每次操作改变一个点是否是关键点。
求所有关键点形成的极小连通子树的边权和的两倍。

输入格式

第一行,两个整数 N、M,其中 M 为宝物的变动次数。
接下来的 N-1 行,每行三个整数 x、y、z,表示村庄 x、y 之间有一条长度为 z 的道路。
接下来的 M 行,每行一个整数 t,表示一个宝物变动的操作。若该操作前村庄 tt 内没有宝物,则操作后村庄内有宝物;若该操作前村庄 t 内有宝物,则操作后村庄内没有宝物。

输出格式

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

数据范围

1N100000,
 1M100000,
 1z109

样例

input

4 5
1 2 30
2 3 50
2 4 60
2
3
4
2
1

output

0
100
220
220
280

思路

DFS序求出之后,关键点按DFS排序后是{a1,a2,...,ak}。
那么所有关键点形成的极小联通子树的边权和的两倍等于dis(a1,a2)+dis(a2,a3)+...+dis(ak1,ak)+dis(ak,a1)
那么求一下 DFS 序,每次操作相当于往集合里加入/删除一个元素。

假设插入 x,它DFS序左右两边分别是 yz。那么答案加上 dis(x,y)+dis(x,z)dis(y,z) 即可。

删除同理。

code

#include <bits/stdc++.h>
using  namespace  std;

typedef long long ll;
typedef unsigned long long ull;
//#pragma GCC optimize(3)
#define pb push_back
#define is insert
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define show(x) cerr<<#x<<" : "<<x<<endl;
//mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
//ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}

const int INF=0x3f3f3f3f;//2147483647;
const int N=1e5+50,M=1e5+50;
const ll mod=998244353;

int n,m;
int head[N];
int tot=0;
struct node {
    int to,nxt;ll val;
}e[M<<1];
void add_edge(int u,int v,ll val){
    e[tot].to=v,e[tot].nxt=head[u],e[tot].val=val,head[u]=tot++;
}

int rt;
int depth[N];
int fa[N][18];
ll dis[N];
queue<int>q;
int dfn[N],idf[N],idx=0;
void dfs(int x,ll step,int pre){
    dfn[x]=++idx;idf[idx]=x;
    dis[x]=step;
    for(int i=head[x];~i;i=e[i].nxt){
        if(e[i].to==pre){
            continue;
        }
        dfs(e[i].to,step+e[i].val,x);
    }
}
void init_bfs(){
    for(int i=1;i<=n;i++){
        depth[i]=INF;
    }
    depth[0]=0;
    depth[rt]=1;
    fa[rt][0]=0;
    q.push(rt);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];~i;i=e[i].nxt){
            int v=e[i].to;
            if(depth[v]>depth[u]+1){
                depth[v]=depth[u]+1;
                fa[v][0]=u;
                q.push(v);
                for(int k=1;k<=17;k++){
                    fa[v][k]=fa[fa[v][k-1]][k-1];
                }
            }
        }
    }
}
int lca(int u,int v){
    if(depth[u]<depth[v])swap(u,v);
    for(int k=17;k>=0;k--){
        if(depth[fa[u][k]]>=depth[v]){
            u=fa[u][k];
        }
    }
    if(u==v){
        return u;
    }
    for(int k=17;k>=0;k--){
        if(fa[u][k]!=fa[v][k]){
            u=fa[u][k];
            v=fa[v][k];
        }
    }
    return fa[u][0];
}
set<int>s;
int vis[N];
int cnt=0;
ll getdis(int u,int v){
    int tmp=lca(u,v);
    return dis[u]+dis[v]-dis[tmp]*2;
}
void solve() {
    memset(head,-1,sizeof head);
    cin>>n>>m;
    for(int i=1;i<=n-1;i++){
        int u,v,val;cin>>u>>v>>val;
        add_edge(u,v,val);
        add_edge(v,u,val);
    }
    rt=1;
    dfs(rt,0,-1);
    init_bfs();
    ll ans=0;
//    for(int i=1;i<=n;i++){
//        cout<<dfn[i]<<" ";
//    }cout<<endl;
    for(int i=1;i<=m;i++){
        int tmp;cin>>tmp;
        tmp=dfn[tmp];
        if(!vis[tmp]) s.is(tmp);
        auto it = s.lower_bound(tmp);
        auto itt = s.upper_bound(tmp);
        int y, z;
        if (it == s.begin()) {
            y = (*--s.end());
        } else {
            y = (*--it);
        }
        if (itt == s.end()) {
            z = (*s.begin());
        } else {
            z = (*itt);
        }
        ll delta=getdis(idf[tmp], idf[y]) + getdis(idf[tmp], idf[z]) - getdis(idf[y], idf[z]);
        if(vis[tmp]){
            s.erase(tmp);
            ans-=delta;
            vis[tmp]=0;
        }
        else {
            vis[tmp]=1;
            ans+=delta;
        }
        cout<<ans<<"\n";
    }
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int __=1;//cin>>__;
    while(__--){
        solve();
    }
    return 0;
}
posted @   illume  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示