zoukankan      html  css  js  c++  java
  • [洛谷P3320] SDOI2015 寻宝游戏

    问题描述

    小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。

    小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物

    输入格式

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

    输出格式

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

    样例输入

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

    样例输出

    0
    100
    220
    220
    280

    解析

    手动模拟之后我们可以发现,对于一个已经确定哪些地方有宝藏的地图,无论从哪个地方出发的路径长度是一样的。稍加归纳我们可以发现,要求的答案就是

    [dis(p_1,p_2)+dis(p_2,p_3)+...+dis(p_{n-1},p_n) ]

    其中(p)是按照DFS序排序后的宝藏地点数组。因此,我们可以用set维护所有有宝藏的地点序列,关键字为DFS序。每次插入都找到插入点在set中的前驱后继,然后用LCA求路径长度修改答案即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <set>
    #include <cmath>
    #define int long long
    #define N 100002
    using namespace std;
    int head[N],ver[N*2],nxt[N*2],edge[N*2],l;
    int n,m,i,f[N][20],dep[N],dfn[N],dis[N],tim;
    bool vis[N];
    struct node{
    	int p;
    	node(int _p){p=_p;}
    	bool operator < (const node &a) const{
    		return dfn[a.p]<dfn[p];
    	}
    };
    set<node> s;
    set<node>::iterator it1,it2;
    int read()
    {
    	char c=getchar();
    	int w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    void insert(int x,int y,int z)
    {
    	l++;
    	ver[l]=y;
    	edge[l]=z;
    	nxt[l]=head[x];
    	head[x]=l;
    }
    void dfs(int x,int pre)
    {
    	dfn[x]=++tim;
    	f[x][0]=pre;
    	dep[x]=dep[pre]+1;
    	for(int i=head[x];i;i=nxt[i]){
    		int y=ver[i];
    		if(y!=pre){
    			dis[y]=dis[x]+edge[i];
    			dfs(y,x);
    		}
    	}
    }
    void init()
    {
    	dfs(1,0);
    	for(int j=0;(1<<(j+1))<=n;j++){
    		for(int i=1;i<=n;i++) f[i][j+1]=f[f[i][j]][j];
    	}
    }
    int LCA(int u,int v)
    {
    	if(dep[u]>dep[v]) swap(u,v);
    	int tmp=dep[v]-dep[u];
    	for(int i=0;(1<<i)<=tmp;i++){
    		if((1<<i)&tmp) v=f[v][i];
    	}
    	if(u==v) return u;
    	for(int i=log2(1.0*n);i>=0;i--){
    		if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
    	}
    	return f[u][0];
    }
    int dist(int x,int y)
    {
    	return dis[x]+dis[y]-2*dis[LCA(x,y)];
    }
    signed main()
    {
    	n=read();m=read();
    	for(i=1;i<n;i++){
    		int u=read(),v=read(),w=read();
    		insert(u,v,w);
    		insert(v,u,w);
    	}
    	init();
    	int ans=0;
    	for(i=1;i<=m;i++){
    		int x=read();
    		if(vis[x]){
    			vis[x]=0;
    			if(s.size()!=1){
    				it1=it2=s.find(node(x));
    				if(it1==s.begin()) it1=s.end();
    				it1--;it2++;
    				if(it2==s.end()) it2=s.begin();
    				ans+=dist((*it1).p,(*it2).p)-dist(x,(*it1).p)-dist(x,(*it2).p);
    			}
    			s.erase(node(x));
    		}
    		else{
    			vis[x]=1;
    			s.insert(node(x));
    			if(s.size()!=1){
    				it1=it2=s.find(node(x));
    				if(it1==s.begin()) it1=s.end();
    				it1--;it2++;
    				if(it2==s.end()) it2=s.begin();
    				ans-=dist((*it1).p,(*it2).p)-dist(x,(*it1).p)-dist(x,(*it2).p);
    			}
    		}
    		printf("%lld
    ",ans); 
    	}
    	return 0;
    }
    
  • 相关阅读:
    oracle 10g 免安装客户端在windows下配置
    sql2005 sa密码
    使用windows live writer 有感
    windows xp SNMP安装包提取
    汉化groove2007
    迁移SQL server 2005 Reporting Services到SQL server 2008 Reporting Services全程截图操作指南
    foxmail 6在使用中的问题
    AGPM客户端连接不上服务器解决一例
    SpringSource Tool Suite add CloudFoundry service
    Java 之 SWing
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11873144.html
Copyright © 2011-2022 走看看