3991: [SDOI2015]寻宝游戏
Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1025 Solved: 508
[ Submit][ Status][ Discuss]
Description
小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。为了简化问题,我们认为最开始时所有村庄内均没有宝物
Input
第一行,两个整数N、M,其中M为宝物的变动次数。
Output
M行,每行一个整数,其中第i行的整数表示第i次操作之后玩家找到所有宝物需要行走的最短路程。若只有一个村庄内有宝物,或者所有村庄内都没有宝物,则输出0。
Sample Input
1 2 30
2 3 50
2 4 60
2
3
4
2
1
Sample Output
100
220
220
280
HINT
1<=N<=100000
Source
每次修改结束后,对于当前确定的关键点,全部拿出来做成虚树
要使答案最优,肯定是虚树上每条边走两边,权值和就是答案了
其实可以这样,把所有关键点按照dfs序排好,只要按照dfs序一个个走过去,最后走回来就行了
这样随便上一个什么数据结构就行了
苟蒻选了替罪羊树。。。。假装是为了学习删除操作吧。。?结果弄了好久
替罪羊树的删除倒是挺奇葩,不会真的把节点抹去,而是给它打个标记,代表它已经不存在了
不过节点仍然存在树中,只是查询操作时不把它记入答案
当一个节点内已经被删除的节点超过一半的时候,就把这个子树暴力重建
复杂度仍然是均摊O(nlogn)
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef double DB;
typedef long long LL;
const DB alpha = 0.666;
const DB belta = 0.500;
const int maxn = 1E5 + 10;
const int T = 18;
struct E{
int to,w; E(){}
E(int to,int w): to(to),w(w){}
};
int n,m,dfs_clock,rt,a,tp,cnt,ch[maxn][2],dfn[maxn],fa[maxn],L[maxn],stk[maxn],Fa[maxn][T],siz[maxn],sz[maxn];
LL Ans,dis[maxn];
bool bo[maxn],ext[maxn];
vector <E> v[maxn];
void Dfs(int x,int from)
{
dfn[x] = ++dfs_clock;
for (int i = 1; i < T; i++) Fa[x][i] = Fa[Fa[x][i-1]][i-1];
for (int i = 0; i < v[x].size(); i++)
{
E e = v[x][i];
if (e.to == from) continue;
dis[e.to] = dis[x] + 1LL * e.w;
L[e.to] = L[x] + 1; Fa[e.to][0] = x; Dfs(e.to,x);
}
}
int maintain(const int &x)
{
sz[x] = ext[x] ? 0 : 1;
sz[x] += sz[ch[x][0]] + sz[ch[x][1]];
siz[x] = 1 + siz[ch[x][0]] + siz[ch[x][1]];
}
bool Judge(const int &x) {return max(siz[ch[x][0]],siz[ch[x][1]]) >= alpha * (DB)(siz[x]) || sz[x] >= belta * (DB)(siz[x]);}
void Insert(int &x,int y)
{
if (x == y) {ext[x] = 1; maintain(x); return;}
if (!x)
{
x = y; ext[x] = siz[x] = 1;
ch[x][0] = ch[x][1] = 0; maintain(x); return;
}
int d = dfn[x] > dfn[y] ? 0 : 1;
Insert(ch[x][d],y); fa[ch[x][d]] = x;
maintain(x); if (Judge(x)) a = x;
}
void Remove(int x,int y)
{
if (x == y)
{
ext[x] = 0; maintain(x);
if (Judge(x)) a = x; return;
}
int d = dfn[x] > dfn[y] ? 0 : 1;
Remove(ch[x][d],y); maintain(x);
if (Judge(x)) a = x;
}
int Rank(int x,int y)
{
if (x == y) return siz[ch[x][0]] - sz[ch[x][0]] + ext[x];
int d = dfn[x] > dfn[y] ? 0 : 1,ret = 0;
if (d == 1) ret = (siz[ch[x][0]] - sz[ch[x][0]] + ext[x]);
return ret + Rank(ch[x][d],y);
}
int Find(int x,int k)
{
int tmp = siz[ch[x][0]] - sz[ch[x][0]] + ext[x];
if (ext[x] && tmp == k) return x;
int d = tmp < k ? 1 : 0; if (d) k -= tmp;
return Find(ch[x][d],k);
}
void Dfs2(int x)
{
if (!x) return; Dfs2(ch[x][0]);
if (ext[x]) stk[++tp] = x; Dfs2(ch[x][1]);
}
int Build(int l,int r)
{
if (l > r) return 0;
int mid = (l + r) >> 1,ret = stk[mid];
ch[ret][0] = Build(l,mid-1);
ch[ret][1] = Build(mid+1,r);
for (int i = 0; i < 2; i++)
if (ch[ret][i]) fa[ch[ret][i]] = ret;
maintain(ret); return ret;
}
void Rebuild(int x)
{
tp = 0; Dfs2(x); int z = fa[x];
int y = fa[x],now = Build(1,tp);
if (x == rt) rt = now,fa[now] = 0;
else {ch[y][ch[y][1] == x] = now; if (now) fa[now] = y;}
while (z) maintain(z),z = fa[z];
}
int LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
for (int i = T - 1; i >= 0; i--)
if (L[p] - (1<<i) >= L[q]) p = Fa[p][i];
if (p == q) return p;
for (int i = T - 1; i >= 0; i--)
if (Fa[p][i] != Fa[q][i])
p = Fa[p][i],q = Fa[q][i];
return Fa[p][0];
}
LL Dis(int x,int y) {return dis[x] + dis[y] - 2LL * dis[LCA(x,y)];}
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret*10 + ch - '0',ch = getchar();
return ret;
}
char s[20];
void Print(LL x)
{
int len = 0; while (x) s[++len] = x % 10LL,x /= 10LL;
for (int i = len; i; i--) putchar(s[i] + '0'); puts("");
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
freopen("test.txt","w",stdout);
#endif
n = getint(); m = getint();
for (int i = 1; i < n; i++)
{
int x = getint(),y,w;
y = getint(); w = getint();
v[x].push_back(E(y,w));
v[y].push_back(E(x,w));
}
L[n / 2] = 1; Dfs(n / 2,0); dfn[n + 1] = -maxn; cnt = 2;
Insert(rt,n + 1); dfn[n + 2] = maxn; Insert(rt,n + 2);
while (m--)
{
int x = getint(); bo[x] ^= 1;
if (bo[x])
{
++cnt; a = 0; Insert(rt,x);
if (cnt == 3) {puts("0"); continue;}
if (a) Rebuild(a); int rk = Rank(rt,x);
int A = rk > 2 ? Find(rt,rk - 1) : Find(rt,cnt - 1);
int B = rk < cnt - 1 ? Find(rt,rk + 1) : Find(rt,2);
Ans += (Dis(A,x) + Dis(B,x) - Dis(A,B)); Print(Ans);
}
else
{
if (cnt == 3)
{
cnt = 2; Ans = 0; puts("0");
Remove(rt,x); continue;
}
int rk = Rank(rt,x);
int A = rk > 2 ? Find(rt,rk - 1) : Find(rt,cnt - 1);
int B = rk < cnt - 1 ? Find(rt,rk + 1) : Find(rt,2);
Ans += (Dis(A,B) - Dis(A,x) - Dis(B,x)); Print(Ans);
a = 0; Remove(rt,x); if (a) Rebuild(a); --cnt;
}
}
return 0;
}