• bzoj3991 lca+dfs序应用+set综合应用


    /*
    给定一棵树,树上会出现宝物,也会有宝物消失
    规定如果要收集树上所有宝物,就要选择一个点开始,到每个宝物点都跑一次,然后再回到那个点 
    现在给定m次修改,每次修改后树上就有一个宝物消失,或者一个宝物出现
    请问在这次操作后,按规则跑一次找到所有宝物的最短路径长度 
    
    显然按规则跑一次找宝物经过的路径长度,就是从根节点开始dfs一次这些点再回到根节点的路径长度
    那么需要将这条路径分解:
        将宝物所在点按dfs序依次排列,收尾相接形成一个环
        总路径就是环上相邻两点的路径之和
    那么每次在环中加入一个点,只要找到环中和其dfs相邻的两个点,加入两条路径即可,删除原来的一条路径即可 
    每次在环中删掉一个点同理
    在增删的过程中保存dfs升序,用set维护结点的dfs即可 
    */
    #include<bits/stdc++.h>
    #include<set>
    using namespace std;
    #define maxn 100005
    #define ll long long
    struct Edge{ll to,nxt,w;}edge[maxn<<1];
    int head[maxn],tot,n,m;
    set<int>s;//存储存在宝箱的点的dfs序 
    set<int>::iterator it;
    int cnt,pos[maxn],id[maxn];//每个点的dfs序,dfs序对应的点 
    ll ans;
    void init(){
        memset(head,-1,sizeof head);
        tot=0;
    }
    void addedge(int u,int v,int w){
        edge[tot].nxt=head[u];edge[tot].w=w;edge[tot].to=v;head[u]=tot++;
    }
    void dfs(int u,int pre){
        pos[u]=++cnt;id[cnt]=u;
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v!=pre)dfs(v,u);
        }
    }
    
    
    int d[maxn],f[maxn][30];
    ll dep[maxn];
    void bfs(){
        queue<int>q;
        q.push(1);
        d[1]=1;dep[1]=0;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i!=-1;i=edge[i].nxt){
                int v=edge[i].to;
                if(d[v])continue;
                d[v]=d[x]+1;
                dep[v]=dep[x]+edge[i].w;
                f[v][0]=x;
                for(int k=1;k<=29;k++)
                    f[v][k]=f[f[v][k-1]][k-1];
                q.push(v);
            }
        }
    }
    ll lca(int u,int v){
        int x=u,y=v;
        if(d[u]<d[v])swap(u,v);
        for(int i=29;i>=0;i--)
            if(d[f[u][i]]>=d[v])u=f[u][i];
        if(u==v){
            return abs(dep[x]-dep[y]);
        }
        for(int i=29;i>=0;i--)
            if(f[u][i]!=f[v][i])u=f[u][i],v=f[v][i];
        u=f[u][0];
        return (dep[x]+dep[y]-2*dep[u]);
    }
    
    int flag[maxn];
    int L(int x){//返回x左边的结点 
        it=s.lower_bound(pos[x]);
        if(it==s.begin())it=s.end();
        --it;
        return id[*it]; 
    }
    int R(int x){//返回x右边的结点 
        it=s.lower_bound(pos[x]);
        ++it;
        if(it==s.end())it=s.begin();
        return id[*it];
    }
    ll query(int x){
        int mul,left,right; 
        if(flag[x]==0){//往集合里加入结点 
            flag[x]=mul=1;
            s.insert(pos[x]);
            left=L(x);right=R(x);
        }
        else {//把集合里的结点删了 
            flag[x]=0;mul=-1;
            left=L(x);right=R(x);
            s.erase(pos[x]);
        }
        if(s.size()==1)return 0;
        ans+=(ll)mul*(lca(left,x)+lca(x,right)-lca(left,right));
        return ans; 
    }
    int main(){
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++){
            ll u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        dfs(1,0);//求出dfs序 
        bfs();//预处理 
        for(int i=1;i<=m;i++){
            int x,u,v;
            scanf("%d",&x);
            printf("%lld
    ",query(x)); 
        }
    }
  • 相关阅读:
    kali Linux的 安装详细步骤
    kali linux与虚拟机Vmware安装vmware tools(主机与虚拟机的文件拖拽)
    利用locust进行压测,检验一下之前搭建的性能监控平台
    记一个比较有趣的缺陷
    使用soupUI模拟(mock)webservice接口
    python操作postgresql数据库
    python接口自动化(二)——封装需要用到的工具类
    Airtest之web自动化(二)——在本地环境运行airtest脚本
    python接口自动化()一)(设计一款自己的接口自动化框架)
    让http服务人类(python之requests做接口测试)
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10512850.html
Copyright © 2020-2023  润新知