• 【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。

    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 leq N,M leq 100000)
    对于全部的数据,(1 leq z leq 10^9)

    Solution

    题意就是叫你维护一棵虚树,求这棵虚树边权和的2倍,事实上,考虑利用dfs序维护,只需要维护相邻dfs序间的距离即可,利用<set>维护dfs序,增加删除的时候算一下影响的距离即可。时间复杂度(O(n log n))

    Code

    #include <stdio.h>
    #include <set>
    #define MN 100005
    #define R register
    #define ll long long
    #define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
    inline int read(){
    	R int x; R bool f; R char c;
    	for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
    	for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
    	return f?-x:x;
    }
    int h[MN],to[MN<<1],nxt[MN<<1],en,n,v[MN<<1];ll dep[MN],nans;
    int sz[MN],son[MN],fa[MN],dfn[MN],top[MN],d[MN],dn,m,re[MN];char op[MN];
    std::set<int> s;bool b[MN];
    inline void ins(int x,int y,int vl){to[++en]=y,nxt[en]=h[x],v[en]=vl,h[x]=en;}
    inline void dfs(int u,int f,ll dis,int dd){
    	dep[u]=dis;fa[u]=f;sz[u]=1;d[u]=dd;
    	for (R int i=h[u]; i; i=nxt[i])
    		if (to[i]!=f){
    			dfs(to[i],u,dis+v[i],dd+1);sz[u]+=sz[to[i]];
    			if (sz[to[i]]>sz[son[u]]) son[u]=to[i];
    		}
    }
    inline void dfs(int u,int tp){
    	dfn[u]=++dn;re[dn]=u;top[u]=tp;if (son[u]) dfs(son[u],tp);
    	for (R int i=h[u]; i; i=nxt[i])
    		if (to[i]!=fa[u]&&to[i]!=son[u]) dfs(to[i],to[i]);
    }
    inline int lca(int x,int y){
    	while(top[x]!=top[y])
    		if (d[top[x]]>d[top[y]])  x=fa[top[x]];
    		else y=fa[top[y]];
    	return d[x]<d[y]?x:y;
    }
    inline int Left(int x){
    	std::set<int>::iterator it=s.find(dfn[x]);
    	if (it==s.begin()) return *(--s.end());
    	return *(--it);
    }
    inline int Right(int x){
    	std::set<int>::iterator it=s.find(dfn[x]);++it;
    	if (it==s.end()) return (*s.begin());
    	return *it;
    }
    inline void upp(int x){
    	nans+=dep[x];s.insert(dfn[x]);
    	R int l=Left(x),r=Right(x);
    	nans-=dep[lca(re[l],x)];
    	nans-=dep[lca(x,re[r])]; 
    	nans+=dep[lca(re[l],re[r])];	
    }
    inline void del(int x){
    	nans-=dep[x];
    	R int l=Left(x),r=Right(x);
    	nans+=dep[lca(re[l],x)];
    	nans+=dep[lca(x,re[r])];
    	nans-=dep[lca(re[l],re[r])];	
    	s.erase(dfn[x]);
    }
    inline ll query(){return nans<<1;}
    int main(){
    	n=read();m=read();for (R int i=1; i<n; ++i){
    		R int x=read(),y=read(),v=read();
    		ins(x,y,v); ins(y,x,v);
    	}dfs(1,0,0,1);dfs(1,1);
    	for (R int i=1,x; i<=m; ++i){
    		b[x=read()]^=1;if (b[x])upp(x);
    		else del(x);printf("%lld
    ",query());
    	}return 0;
    }
    
  • 相关阅读:
    A1052. Linked List Sorting (25)
    A1032. Sharing (25)
    A1022. Digital Library (30)
    A1071. Speech Patterns (25)
    A1054. The Dominant Color (20)
    A1060. Are They Equal (25)
    A1063. Set Similarity (25)
    电子码表
    矩阵键盘
    对象追踪、临时对象追踪、绝对坐标与相对坐标
  • 原文地址:https://www.cnblogs.com/Melacau/p/BZOJ3991.html
Copyright © 2020-2023  润新知