您的位置:首页 > 其它

Bzoj-3991 寻宝游戏(dfs序)

2017-07-30 21:29 274 查看
 小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<=N<=100000

1<=M<=100000

对于全部的数据,1<=z<=10^9

分析:相当于给你一些树上的点集问你这些点集和一些必要点构成的子树的边权值和,然后有一个技巧就是,如果我们把这些点按dfs序排序,那么边权和的两倍就等于相邻两点间的距离再加上序列中第一个点到最后一个点的距离,所以我们可以把所有点按dfs序放进一个set里边,然后动态维护这个序列对答案的影响就可以了.

#include <bits/stdc++.h>
#define MOD 1000000007
#define N 100005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
vector<pii> G
;
int n,m,x,y,c,t,Time,dfn
,f
[32],deep
;
ll deep_dis
,ans;
inline int read()
{
int x=0;char ch=getchar();
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
struct cmp
{
bool operator () (int a,int b)
{
return dfn[a] < dfn[b];
}
};
set<int,cmp> s;
void dfs(int u,int fa,ll d_dis,int d)
{
deep_dis[u] = d_dis;
deep[u] = d;
dfn[u] = ++Time;
for(int i = 0;i < G[u].size();i++)
{
int v = G[u][i].first,val = G[u][i].second;
if(v == fa) continue;
f[v][0] = u;
dfs(v,u,d_dis+val,d+1);
}
}
void init()
{
f[1][0] = 1;
for(int j = 1;(1<<j) <= n;j++)
for(int i = 1;i <= n;i++)
f[i][j] = f[f[i][j-1]][j-1];
}
int LCA(int u,int v)
{
if(deep[u] < deep[v]) swap(u,v);
int d = deep[u] - deep[v];
for(int i = 0;i < 30;i++)
if((1<<i) & d) u = f[u][i];
if(u == v) return u;
for(int i = 29;i >= 0;i--)
{
if(f[u][i] != f[v][i])
{
u = f[u][i];
v = f[v][i];
}
}
u = f[u][0];
return u;
}
ll dis(int x,int y)
{
return deep_dis[x] + deep_dis[y] - 2*deep_dis[LCA(x,y)];
}
void Erase(int x)
{
set<int,cmp> :: iterator it = s.find(x),last;
last = s.end(),last--;
ans -= dis(*(s.begin()),*last);
if(it != s.begin())
{
it--;
ans -= dis(*it,x);
it++;
}
if(it != last)
{
it++;
ans -= dis(*it,x);
it--;
}
if(it != s.begin() && it != last)
{
last = ++it;
it--,it--;
ans += dis(*it,*last);
}
s.erase(x);
if(s.empty()) return;
it = s.begin(),last = s.end(),last--;
ans += dis(*it,*last);
}
void Insert(int x)
{
set<int,cmp> :: iterator it,last;
if(!s.empty())
{
last = s.end(),last--;
ans -= dis(*(s.begin()),*last);
}
s.insert(x),it = s.find(x);
last = s.end(),last--;
if(it != s.begin())
{
it--;
ans += dis(*it,x);
it++;
}
if(it != last)
{
it++;
ans += dis(*it,x);
it--;
}
if(it != s.begin() && it != last)
{
last = ++it;
it--,it--;
ans -= dis(*it,*last);
}
it = s.begin(),last = s.end(),last--;
ans += dis(*it,*last);
}
int main()
{
n = read(),m = read();
for(int i = 1;i < n;i++)
{
x = read(),y = read(),c = read();
G[x].push_back(make_pair(y,c));
G[y].push_back(make_pair(x,c));
}
dfs(1,0,0,0);
init();
for(int i = 1;i <= m;i++)
{
t = read();
if(s.find(t) != s.end()) Erase(t);
else Insert(t);
printf("%lld\n",ans);
}
}
/*/
4 10
1 2 30
2 3 50
2 4 60
/*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: