bzoj 3991: [SDOI2015]寻宝游戏 — dfs序,set
Contents
3991: [SDOI2015]寻宝游戏
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
1 2 30
2 3 50
2 4 60
2
3
4
2
1
Sample Output
0
100
220
220
280
100
220
220
280
HINT
1<=N<=100000
1<=M<=100000
对于全部的数据,1<=z<=10^9
Source
可以证明一个结论,最优方案就是把所有关键点排序,相邻点的路径和加上两端点的路径
那么就是可以维护一个set,维护dfs序,每次操作就是插入和删除,计算相邻点的变化就好
#include<set>
#include<cmath>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 1000000007
#define ll long long
#define N 200010
inline int rd()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int lj[N],fro[N],to[N],cnt;
ll v[N];
void add(int a,int b,int c){fro[++cnt]=lj[a];to[cnt]=b;lj[a]=cnt;v[cnt]=c;}
int n,m;
int dep[N],dfn[N],tim;
int fa[N][21];
ll dis[N];
void dfs(int x,int f)
{
dep[x]=dep[f]+1;
dfn[x]=++tim;
fa[x][0]=f;
for(int i=1;i<21;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=lj[x];i;i=fro[i])
{
if(to[i]==f) continue;
dis[to[i]]=dis[x]+v[i];
dfs(to[i],x);
}
}
set<pair<int,int> >s;
set<pair<int,int> >::iterator it,bg,ed,b2,i2,i1;
#define mp make_pair
bool vs[N];
ll ans;
int LCA(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
for(int i=20;i>=0;i--) if(dep[fa[a][i]]>=dep[b]) a=fa[a][i];
if(a==b) return a;
for(int i=20;i>=0;i--) if(fa[a][i]^fa[b][i]) a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
ll fd(int a,int b)
{
int l=LCA(a,b);
return dis[a]+dis[b]-dis[l]*2;
}
int main()
{
n=rd();m=rd();
for(int i=1,x,y,z;i<n;i++)
{
x=rd();y=rd();z=rd();
add(x,y,z);add(y,x,z);
}
dfs(1,0);
int x,y,z;
pair<int,int>p;
while(m--)
{
x=rd();
p=mp(dfn[x],x);
b2=bg=s.begin();ed=s.end();
if(s.size()) b2++,ed--;
if(!vs[x])
{
vs[x]=1;
if(!s.size());
else if(s.size()==1) ans=fd((*bg).second,x)*2;
else
{
i1=it=s.lower_bound(p);
if(it==s.end()) i1--,y=(*bg).second,z=(*i1).second;
else if(it==s.begin()) y=(*bg).second,z=(*ed).second;
else i1--,y=(*i1).second,z=(*it).second;
ans-=fd(y,z);
ans+=fd(x,y)+fd(x,z);
}
s.insert(p);
}
else
{
vs[x]=0;
if(s.size()<=2) ans=0;
else
{
i1=i2=it=s.lower_bound(p);i2++;
if(i2==s.end()) i1--,y=(*bg).second,z=(*i1).second;
else if(it==s.begin()) y=(*b2).second,z=(*ed).second;
else i1--,y=(*i1).second,z=(*i2).second;
ans+=fd(y,z);
ans-=fd(x,y)+fd(x,z);
}
s.erase(p);
}
printf("%lld\n",ans);
}
return 0;
}
发表评论