P3320 [SDOI2015]寻宝游戏

题目

P3320 [SDOI2015]寻宝游戏

做法

很巧妙的一种思路,懂了之后觉得大水题

首先要知道:在一棵树上标记一些点,然后从任意一点出发,遍历所有的的最小路径为\(dfs\)序从小到大遍历

那就把点丢到\(set\)里面,然后找\(dfs\)的前驱与后继计算路径就好了

其实也有点虚树的思想,只管标记的这几个点

My complete code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<ctime>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
typedef long long LL;
const LL maxn=1e5+9;
inline LL Read(){
	LL x(0),f(1);char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
struct node{
	LL to,next,d;
}dis[maxn<<1];
LL n,T,num,ans,tot;
LL head[maxn],dfn[maxn],pos[maxn],inc[maxn][25],d[maxn],dep[maxn],visit[maxn];
inline void Add(LL u,LL v,LL d){
	dis[++num]=(node){v,head[u],d},head[u]=num;
}
void Dfs(LL u){
	dfn[u]=++tot,pos[tot]=u;
	for(LL i=1;i<=21;++i)
	    inc[u][i]=inc[inc[u][i-1]][i-1];
	for(LL i=head[u];i;i=dis[i].next){
		LL v(dis[i].to);
		if(v==inc[u][0])
		    continue;
		d[v]=d[u]+dis[i].d,inc[v][0]=u,dep[v]=dep[u]+1;
		Dfs(v);
	}
}
inline LL Lca(LL x,LL y){
	if(dep[x]<dep[y])swap(x,y);
	for(LL i=20;i>=0;--i)
	    if(dep[inc[x][i]]>=dep[y])
	        x=inc[x][i];
	if(x==y)return x;
    for(LL i=20;i>=0;--i)
        if(inc[x][i]!=inc[y][i])
            x=inc[x][i],y=inc[y][i];
    return inc[x][0];
}
set<LL> Set;
set<LL> :: iterator it,pre,next;
inline void Query(LL x){
	it=Set.find(dfn[x]);
	if(it==Set.begin()){
		pre=Set.end(),--pre;
	}else{
		pre=it,--pre;
	}
	next=it,++next;
	if(next==Set.end())
	    next=Set.begin();
	it=Set.find(dfn[x]);
}
inline LL Change(){
	return 2*d[pos[*it]]+d[pos[*next]]+d[pos[*pre]]-2*d[Lca(pos[*pre],pos[*it])]-2*d[Lca(pos[*next],pos[*it])];
}
inline LL Split(){
	return d[pos[*pre]]+d[pos[*next]]-2*d[Lca(pos[*pre],pos[*next])];
}
int main(){
	n=Read(),T=Read();
	for(LL i=1;i<n;++i){
		LL u(Read()),v(Read()),d(Read());
	    Add(u,v,d),Add(v,u,d);
	}
	Dfs(1);
	while(T--){
		LL now(Read());
		if(visit[now]){
			Query(now),
			ans-=Change(),ans+=Split(),
			Set.erase(dfn[now]);
		}else{
			Set.insert(dfn[now]),
			Query(now),
			ans-=Split(),ans+=Change();
		}
		visit[now]^=1;
		printf("%lld\n",ans);
	}
	return 0;
}/*
*/
posted @ 2019-01-20 16:09  y2823774827y  阅读(143)  评论(0编辑  收藏  举报