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; }
发表评论