3991: [SDOI2015]寻宝游戏

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 1025  Solved: 508
[Submit][Status][Discuss]

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

Sample Output

0
100
220
220
280

HINT

1<=N<=100000

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

Source

Round 1 感谢yts1999上传

[Submit][Status][Discuss]



每次修改结束后,对于当前确定的关键点,全部拿出来做成虚树

要使答案最优,肯定是虚树上每条边走两边,权值和就是答案了

其实可以这样,把所有关键点按照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 DMCfreopen("DMC.txt","r",stdin);freopen("test.txt","w",stdout);#endifn = 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;
}

3991: [SDOI2015]寻宝游戏相关推荐

  1. BZOJ 3991: [SDOI2015]寻宝游戏

    随便选一个点当做根,跑每个点的深度(为了求LCA)d [ u ] ,和到根节点的距离(为了更新答案) l [ u ] 我们发现,由关键点和他们的LCA构成的虚树(其实就是忽略其他节点),由于还要回到原 ...

  2. 【BZOJ 3991】 [SDOI2015]寻宝游戏

    3991: [SDOI2015]寻宝游戏 Time Limit: 40 Sec Memory Limit: 128 MB Submit: 251 Solved: 137 [Submit][Status ...

  3. SDOI2015寻宝游戏 dfs序+set

    SDOI2015寻宝游戏 好像是一道虚树入门题? 虚树???不会不会我弱死了.. Solution: 关键点间的最小路径,就是在保证尽量少走重复路的前提下走出来的一条经过所有关键点的路径. 基于这个思 ...

  4. 洛谷 P3320: bzoj 3991: LOJ 2182: [SDOI2015]寻宝游戏

    题目传送门:LOJ #2182. 题意简述: 一棵 \(n\) 个节点的树,边有边权. 每个点可能是关键点,每次操作改变一个点是否是关键点. 求所有关键点形成的极小联通子树的边权和的两倍. 题解: 有 ...

  5. 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)

    被\(STL\)坑害了一个晚上,真的菜的没救了啊. 准确的说是一个叫\(reverse\ iterator\)的东西,就是我们经常用的\(rbegin()\) 有一个非常重要的性质 在反向迭代器中,+ ...

  6. 【bzoj3991】[SDOI2015]寻宝游戏 树链的并+STL-set

    题目描述 给出一棵树,初始每个点都是非必经的.多次改变某个点的必经状态,并询问从任意一个点出发,经过所有必经的点并回到该点的最小路程. 输入 第一行,两个整数N.M,其中M为宝物的变动次数. 接下来的 ...

  7. 【SDOI2015】【BZOJ3991】寻宝游戏

    Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可 ...

  8. 河北工业大学c语言寻宝游戏,计算机技术基础(c语言)课程设计寻宝游戏.doc

    计算机技术基础(c语言)课程设计寻宝游戏 计算机技术基础(c语言)课程设计 寻宝游戏 #include #include #include #include #include #define ESC ...

  9. hdu 6289 寻宝游戏

    寻宝游戏 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others) Total Sub ...

  10. 寻宝游戏 - 利用iBeacon特性设计的iOS线下寻宝游戏 - 物联网小游戏

    寻宝游戏 - 利用iBeacon特性设计的iOS线下寻宝游戏 作者简介 科科香,程序员 方向:IoT,方案集成,喜好各种新鲜东东 转载请注明出处 iBeacon简介 iBeacon(下面简称Beaco ...

最新文章

  1. java使用jsp servlet来防止csrf 攻击的实现方法
  2. Qt——鼠标拖动调整窗口大小
  3. window7不要光盘修复计算机,Win7若崩溃了就靠它——Win7系统修复光盘制作方法解析...
  4. linux shell 数组对比,bash shell之数组使用(牛逼篇)
  5. Linux shell去除字符串中所有空格
  6. 资深大牛推荐学习路线建议
  7. 可逆矩阵的秩等于矩阵的阶数_矩阵论一些总结点
  8. 【Clickhouse】Clickhouse 运算符 操作符 算术,比较,取整,逻辑,哈希,条件 字符串函数
  9. 数据分析写作——程序员的另外一种输出
  10. 6 自定义控件之屏蔽控件的设计时属性
  11. python快速开发框架_GitHub - lee2029/pyui4win: 一个用python实现业务逻辑、用xml和html/css/js描述界面的windows程序的快速开发框架...
  12. [转]20个优秀网站助你征服CSS
  13. 设置linux中docker中的mysql开机自动启动
  14. QSqlRelationTableModel使用示例
  15. 一米优店宝-淘宝店铺优化软件v1.0官方
  16. 项目管理笔记-第十章 项目沟通管理
  17. unity android判断是否横屏,android 强制设置横屏 判断是横屏还是竖屏
  18. Matlab:添加和删除表行
  19. 华为测试岗面试经验(附面试流程)
  20. 自定义View练习 - 汉字键盘

热门文章

  1. MATLAB 数学应用 初等数学 绘制虚数和复数数据图
  2. 面试高频智力题 100层楼两个鸡蛋找出临界点的最多次数 (直接分析法,非动态规划思路)
  3. SWUN 1431 - 伊邪那美(Ⅱ)
  4. 词性标注 python
  5. 云的基本概念(公有云、私有云、混合云, IaaS、PaaS、SaaS)
  6. VS2013+OpenCV2.4.10配置
  7. android 应用市场图尺寸,【干货】最新App应用市场截图尺寸大全
  8. 高通Thermal Overview之thermal-engine
  9. 如何做一个优秀的管理者
  10. PHP外包简易加密后门