zoukankan      html  css  js  c++  java
  • BZOJ3991: [SDOI2015]寻宝游戏(set+lca / 虚树)


    BZOJ2286: [Sdoi2011]消耗战##

      Time Limit: 40 Sec
      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
      

    题目地址:  BZOJ3991: [SDOI2015]寻宝游戏

    题目大意: 已经很简洁了

    题解:

      本来是想做虚树来做这道题的
      突然发现 set+lca 炒鸡简单
      
      用一个 set 维护 dfn
      插入操作:我们可以将一点 x 插入到 set 中,将上一次的答案加上 x 点到其前驱以及后继点的路径长,再减去该两点之间的路径长。
      (insert_{ans}(x)=ans_{last}-dis(before,after)+dis(x,before)+dis(x,after))
      
      删除操作:我们可以将上一次答案加上待删除的点x的前驱和后继之间的路径长,再减去分别到前驱后后继的路径。
      (erase_{ans}(x)=ans_{last}+dis(before,after)-dis(x,before)-dis(x,after))
      
      其中dis为
      (dis(x,y)=disigr(LCA(x,y),xigl)+disigr(LCA(x,y),yigl))
      我们可以用树剖或倍增求lca
      再加上最后一个到第一个的距离就完事了
      参考 https://www.luogu.org/problemnew/solution/P3320


    set + 倍增lca

    #include <cstdio> 
    #include <algorithm>
    #include <set>
    #define ll long long
    using namespace std;
    const int N=1e5+5;
    int n,Q,cnt;
    int last[N],fa[N][18];
    ll num,ans,dis[N][18];
    bool mark[N];
    set<int> q;
    struct edge{
    	int to,val,next;
    }e[N<<1];
    inline void add_edge(int u,int v,int w){
    	e[++cnt]=(edge){v,w,last[u]};last[u]=cnt;
    	e[++cnt]=(edge){u,w,last[v]};last[v]=cnt;
    }
    int ind,pos[N],sop[N],dep[N];
    void dfs(int u){
    	pos[u]=++ind;
    	sop[ind]=u;
    	for(int i=last[u];i;i=e[i].next){
    		int v=e[i].to;
    		if(v==fa[u][0])continue;
    		fa[v][0]=u;dis[v][0]=e[i].val;
    		dep[v]=dep[u]+1;
    		dfs(v);
    	}
    }
    ll lca(int a,int b){
    	ll res=0;
    	if(dep[a]<dep[b])swap(a,b);
    	for(int i=17;i>=0;i--)
    		if(dep[fa[a][i]]>=dep[b]){
    			res+=dis[a][i];
    			a=fa[a][i];
    		}
    	for(int i=17;i>=0;i--)
    		if(fa[a][i]!=fa[b][i]){
    			res+=dis[a][i]+dis[b][i];
    			a=fa[a][i];b=fa[b][i];
    		}
    	if(a==b)return res;
    	res+=dis[a][0]+dis[b][0];
    	return res;
    }
    ll Dis(int a,int b){
    	a=sop[a];b=sop[b];
    	return lca(a,b);
    }
    void Insert(int x){
    	mark[x]=1;x=pos[x];
    	q.insert(x);
    	int lst=*(--q.find(x));
    	int nxt=*(++q.find(x));
    	if(lst>=1)ans+=Dis(lst,x);
    	if(nxt<=n)ans+=Dis(x,nxt);
    	if(1<=lst && nxt<=n)ans-=Dis(lst,nxt);
    }
    void Erase(int x){
    	mark[x]=0;x=pos[x];
    	int lst=*(--q.find(x));
    	int nxt=*(++q.find(x));
    	if(lst>=1)ans-=Dis(lst,x);
    	if(nxt<=n)ans-=Dis(x,nxt);
    	if(1<=lst && nxt<=n)ans+=Dis(lst,nxt);
    	q.erase(x);
    }
    int main(){
    	scanf("%d%d",&n,&Q);
    	for(int i=1;i<n;i++){
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		add_edge(u,v,w);
    	}
    	dep[1]=1;
    	dfs(1);
    	for(int j=1;j<=17;j++)
    		for(int i=1;i<=n;i++){
    			fa[i][j]=fa[fa[i][j-1]][j-1];
    			dis[i][j]=dis[i][j-1]+dis[fa[i][j-1]][j-1];
    		}
    	q.insert(0);
    	q.insert(n+1);
    	while(Q--){
    		int x;
    		scanf("%d",&x);
    		if(!mark[x])Insert(x);
    		else Erase(x);
    		int Sta=*(++q.find(0));
    		int End=*(--q.find(n+1));
    		if(1<=Sta && End<=n)num=Dis(Sta,End);
    		printf("%lld
    ",ans+num);
    	}
    	return 0;
    }
    

    set + 树剖lca

    
    

    虚树

    
    


      作者:skl_win
      出处:https://www.cnblogs.com/shaokele/
      本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    如果你的领导是力量型,你在汇报工作时应该注意()。
    项目管理的10项原则
    扑克k,你知道的人物吗?
    搭建属于您自己的软件版本控制
    Android保持屏幕常亮的方法
    BMP图像数据格式详解
    Android终止线程的方法
    使用ContentProvider访问其他应用的SharedPreferences数据
    android gps定位LocationManager
    Android属性之build.prop生成过程分析
  • 原文地址:https://www.cnblogs.com/shaokele/p/9510116.html
Copyright © 2011-2022 走看看