zoukankan      html  css  js  c++  java
  • 【BZOJ3991】 寻宝游戏

    Time Limit: 1000 ms   Memory Limit: 128 MB

    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。

     

    Sample Input

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

    Sample Output

      0
      100
      220
      220
      280

    HINT

       1<=N<=100000


      1<=M<=100000

      对于全部的数据,1<=z<=10^9

    题解

      看得出来答案是有效虚树的边权之和的两倍,和在哪里出发并无关系。

      对于当前所有有效点,按dfn排序后顺次到达,总路程刚好是总边权的两倍。

      用一个set维护有效点的dfn值,插入一个点$x$的时候,总答案减去dfn序中前一个有效点$u$到后一个有效点$v$的距离,再加上$u$到$x$,$x$到$v$的距离。

      删除一个点$x$同理,删除$u$到$x$、$x$到$v$的距离,再加上$u$到$v$的距离即可。

      注意特判前后是空的情况。

      这样的答案还缺一个值,就是最后一个点走到初始点的距离,加上就好。


    #include <cstdio>
    #include <cmath>
    #include <set>
    using namespace std;
    typedef long long ll;
    typedef set<int>::iterator si;
    const int N=100010,Bas=19;
    int n,m,bas,h[N],tot,dep[N],pre[N][Bas],dfn[N],who[N],tmcnt,state[N],sum;
    ll dis[N],ans;
    set<int> s;
    struct Edge{int v,w,next;}g[N*2];
    inline void addEdge(int u,int v,int w){
        g[++tot].v=v; g[tot].w=w; g[tot].next=h[u]; h[u]=tot;
    }
    void predfs(int u,int fa,int Dep,int Dis){
        dfn[u]=++tmcnt;
        who[tmcnt]=u;
        dep[u]=Dep;
        dis[u]=Dis;
        pre[u][0]=fa;
        for(int i=1;i<=bas;i++) pre[u][i]=pre[pre[u][i-1]][i-1];
        for(int i=h[u],v;i;i=g[i].next)
            if((v=g[i].v)!=fa)
                predfs(v,u,Dep+1,Dis+g[i].w);
    }
    int getlca(int a,int b){
        if(dep[a]<dep[b]) swap(a,b);
        for(int i=bas;i>=0;i--) 
            if(dep[pre[a][i]]>=dep[b]) a=pre[a][i];
        if(a==b) return a;
        for(int i=bas;i>=0;i--)
            if(pre[a][i]!=pre[b][i]) a=pre[a][i],b=pre[b][i];
        return pre[a][0];
    }
    int getpre(int u){
        si p=s.lower_bound(dfn[u]);
        if(p==s.begin()) return -1;
        p--;
        return who[*p];
    }
    int getnex(int u){
        si p=s.lower_bound(dfn[u]+1);
        if(p==s.end()) return -1;
        return who[*p];
    }
    ll getdis(int x,int y){return dis[x]+dis[y]-dis[getlca(x,y)]*2;}
    ll count(){
        if(sum<=1) return 0;
        si a=s.begin();
        si b=s.end();
        b--;
        return getdis(who[*a],who[*b]);
    }
    int main(){
        scanf("%d%d",&n,&m);
        bas=(int)log2(n)+1;
        for(int i=1,u,v,w;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            addEdge(u,v,w);
            addEdge(v,u,w);
        }
        predfs(1,0,1,0);
        int x;
        sum=ans=0;
        while(m--){
            scanf("%d",&x);    
            if(!state[x]){
                sum++;
                state[x]=1;
                int a=getpre(x),b=getnex(x);    
                s.insert(dfn[x]);
                if(sum>1){
                    if(a==-1)
                        ans+=getdis(x,b);
                    else if(b==-1)
                        ans+=getdis(a,x);
                    else{
                        ans-=getdis(a,b);
                        ans+=getdis(a,x)+getdis(x,b);
                    }
                }
            }
            else{
                sum--;
                state[x]=0;
                int a=getpre(x),b=getnex(x);
                s.erase(dfn[x]);
                if(a!=-1) ans-=getdis(a,x);
                if(b!=-1) ans-=getdis(x,b);
                if(a!=-1&&b!=-1) ans+=getdis(a,b);
            }
            printf("%lld
    ",ans+count());
        }
        return 0;
    }
    奇妙代码
  • 相关阅读:
    Interview with BOA
    Java Main Differences between HashMap HashTable and ConcurrentHashMap
    Java Main Differences between Java and C++
    LeetCode 33. Search in Rotated Sorted Array
    LeetCode 154. Find Minimum in Rotated Sorted Array II
    LeetCode 153. Find Minimum in Rotated Sorted Array
    LeetCode 75. Sort Colors
    LeetCode 31. Next Permutation
    LeetCode 60. Permutation Sequence
    LeetCode 216. Combination Sum III
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/8007253.html
Copyright © 2011-2022 走看看