• bzoj3991 [SDOI2015]寻宝游戏


    Description

     小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物

    Input

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

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

    Output

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

    zkw线段树维护有宝藏村庄在原树中的dfs序并支持查询前驱后继
    dfs序相邻(包括dfs序最大和最小的点间)的点间距离之和即为最短路程
    树链剖分求lca以及两点间距离
    #include<cstdio>
    inline int input(){
        int x=0,c=getchar();
        while(c>57||c<48)c=getchar();
        while(c>47&&c<58)x=x*10+c-48,c=getchar();
        return x;
    }
    const int N=100055;
    typedef long long i64;
    int n,m;
    int es[N*2],enx[N*2],ev[N*2],e0[N],ep=2;
    int sz[N],son[N],dep[N],top[N],fa[N],id[N],rid[N],idp=1;
    int st[N];
    i64 len[N],ans=0;
    void f1(int w,int pa){
        fa[w]=pa;
        dep[w]=dep[pa]+1;
        sz[w]=1;
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u==pa)continue;
            len[u]=len[w]+ev[i];
            f1(u,w);
            sz[w]+=sz[u];
            if(sz[u]>sz[son[w]])son[w]=u;
        }
    }
    void f2(int w,int tp){
        top[w]=tp;
        rid[id[w]=idp++]=w;
        if(son[w])f2(son[w],tp);
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=fa[w]&&u!=son[w])f2(u,u);
        }
    }
    i64 dist(int x,int y){
        x=rid[x];y=rid[y];
        int a=top[x],b=top[y],c;
        i64 s=len[x]+len[y];
        while(a!=b){
            if(dep[a]<dep[b])c=a,a=b,b=c,c=x,x=y,y=c;
            x=fa[a];a=top[x];
        }
        s-=(dep[x]<dep[y]?len[x]:len[y])*2;
        return s;
    }
    inline int min(int a,int b){return a<b?a:b;}
    inline int max(int a,int b){return a>b?a:b;}
    inline void mins(int&a,int b){if(a>b)a=b;}
    inline void maxs(int&a,int b){if(a<b)a=b;}
    const int inf=0x3f3f3f3f;
    int mn[262144],mx[262144];
    void ins(int x){
        int w=x+131074;
        mn[w]=mx[w]=x;
        for(w>>=1;w;w>>=1){
            mins(mn[w],x);
            maxs(mx[w],x);
        }
    }
    void del(int x){
        int w=x+131074;
        mn[w]=inf;
        mx[w]=-inf;
        for(w>>=1;w;w>>=1){
            int lc=w<<1,rc=lc^1;
            mn[w]=min(mn[lc],mn[rc]);
            mx[w]=max(mx[lc],mx[rc]);
        }
    }
    i64 cal(int x){
        int pv=-inf,nx=inf;
        for(int w=x+131074;w!=1;w>>=1){
            if(w&1)maxs(pv,mx[w^1]);
            else mins(nx,mn[w^1]);
        }
        if(nx==inf)nx=mn[1];
        if(pv==-inf)pv=mx[1];
        return dist(pv,x)+dist(nx,x)-dist(pv,nx);
    }
    int main(){
        for(int i=1;i<262144;i++)mn[i]=inf,mx[i]=-inf;
        n=input();m=input();
        for(int i=1,a,b,c;i<n;i++){
            a=input();b=input();c=input();
            es[ep]=b;enx[ep]=e0[a];ev[ep]=c;e0[a]=ep++;
            es[ep]=a;enx[ep]=e0[b];ev[ep]=c;e0[b]=ep++;
        }
        f1(1,0);f2(1,1);
        while(m--){
            int w=input();
            if(st[w]){
                st[w]=0;
                ans-=cal(id[w]);
                del(id[w]);
            }else{
                st[w]=1;
                ins(id[w]);
                ans+=cal(id[w]);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Spark 基本概念及入门
    Cron 表达式详解
    VmWare 网络模式
    微信、支付宝各种支付退款
    Spring Security OAuth2 SSO 单点登录
    Git 入门详解
    基于Spring Boot 2.x 的 Spring Cloud Admin 实践
    Git 提交规范
    Linux 安装 Mysql8.0
    Docker入门
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5498006.html
Copyright © 2020-2023  润新知