P3345 [ZJOI2015]幻想乡战略游戏

题目描述

傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。

在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有\(n\)块空地,这些空地被\(n-1\)条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。

在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点\(u\)上,并且空地\(v\)上有\(d_v\)个单位的军队,那么幽香每天就要花费\(d_v\times dist(u,v)\)的金钱来补给这些军队。

由于幽香需要补给所有的军队,因此幽香总共就要花费为\(\sum d_v\times dist(u,v)\),其中\(1\le V\le N\)的代价。其中\(dist(u,v)\)表示\(u\)和\(v\)在树上的距离(唯一路径的权和)。

因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。

但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。

输入输出格式

输入格式:

第一行两个数\(n\)和\(Q\)分别表示树的点数和幽香操作的个数,其中点从\(1\)到\(n\)标号。

接下来\(n-1\)行,每行三个正整数\(a,b,c\),表示\(a\)和\(b\)之间有一条边权为\(c\)的边。

接下来\(Q\)行,每行两个数\(u,e\),表示幽香在点\(u\)上放了\(e\)单位个军队(如果\(e<0\),就相当于是幽香在\(u\)上减少了\(|e|\)单位个军队,说白了就是\(d_u←d_u+e\)。数据保证任何时刻每个点上的军队数量都是非负的。

输出格式:

对于幽香的每个操作,输出操作完成以后,每天的最小花费,也即如果幽香选择最优的补给点进行补给时的花费。

说明

对于所有数据,\(1\le c\le 1000, 0\le|e|\le 1000, n\le 10^5\),\(Q\le 10^5\) 非常神奇的是,对于所有数据,这棵树上的点的度数都不超过\(20\),且\(N,Q\ge1\)


花了很久才弄明白啊,我这个智力可能不适合做\(OI\)...


简单来说,这题就是一个修改点权询问带权重心的题。

首先我们考虑随便选择一个点作为答案,为了方便,暂且将这个点当做树的根。

考虑将答案移向相邻点(也相当于换根)的条件,令\(sumd_i\)代表\(i\)点的子树的带权大小也就是\(\sum\limits_{v\in i}d_v\)。若想从\(now\)移动到\(v\),设\(dis_{now,v}\)代表从\(now\)到\(v\)的长度。

那么移动后的答案改变量就是\((sumd_{now}-sumd_v-sumd_v)\times dis_{now,v}\),于是当\(sumd_{now}<sumd_v\times 2\)时,我们进行移动,可以简单的证明,每个点最多只有一个儿子可以移动过去。

暴力移动并进行换根是行不通的,考虑构造点分树进行移动与换根。


点分树有几个显著特点

  1. 树高\(\log\),维护信息暴力跳就可以了
  2. 点分树的子树是原树的一个联通快,这也是在点分树上进行换根操作的基础。

对这个题,我们先建好点分树,然后对每个点维护几个信息。

\(d_i\)表示自己点权,\(sumd_i\)表示\(i\)点点分树的子树\(\sum d\),\(sumf_i\)表示点分树子树所有点到点分树父亲的答案(如果一个点没有父亲,可以简单的指向它自己)

修改操作比较简单,直接在点分树向上暴力修改即可。

查询的时候,先选定点分树的根,然后遍历点分树的儿子比较\(sumd\),注意这里点分树的\(sumd\)和本身原树上儿子的\(sumd\)的值是一样的,所以更严谨的说其实找的还是原树的儿子。

如果可以移动,那么答案点一定在点\(v\)的子树中(点分树的),然后我们考虑把根换成\(v\)

如图,\(now\)是当前节点,\(v\)是应该移向的分治子树,\(w\)是在\(v\)的子树中与\(now\)在原树中直接相连的点。

然后我们直接把\(now\)及绿色子树的点权给\(w\),并在外部加上\(now\)和绿色子树本身的答案。这样就把\(v\)子树外面的点等价到了内部并且统计了外部答案。注意更新了\(w\)之后还要把\(w\)父亲的信息同样更新。

然后递归进行这个过程直到找不到一个儿子可以去移动即可,递归回溯时要把\(now\)加在\(w\)的信息进行还原。


需要\(RMQLCA\)进行\(O(1)\)的查询两点间距离保证复杂度为\(O(n\log^2n)\),事实上树剖好像也可以跑。

注意这个做法会被菊花树卡掉因为点分树儿子个数可能会很多但题目保证了度数就没关系了啦。


Code:

  1. #include <cstdio>
  2. #include <vector>
  3. #define ll long long
  4. const int N=2e5+10;
  5. int head[N],to[N],Next[N],edge[N],cnt;
  6. void add(int u,int v,int w)
  7. {
  8. to[++cnt]=v,edge[cnt]=w,Next[cnt]=head[u],head[u]=cnt;
  9. }
  10. namespace RMQLCA
  11. {
  12. ll dis[N];int dep[N],st[N][20],dfn[N],Log[N],dfs_clock;
  13. void dfs(int now,int fa)
  14. {
  15. dep[now]=dep[fa]+1;
  16. st[dfn[now]=++dfs_clock][0]=now;
  17. for(int v,i=head[now];i;i=Next[i])
  18. if((v=to[i])!=fa)
  19. dis[v]=dis[now]+edge[i],dfs(v,now),st[++dfs_clock][0]=now;
  20. }
  21. void init()
  22. {
  23. dfs(1,0);
  24. for(int i=2;i<=dfs_clock;i++) Log[i]=Log[i>>1]+1;
  25. for(int j=1;j<=18;j++)
  26. {
  27. for(int x,y,i=1;i<=dfs_clock-(1<<j)+1;i++)
  28. {
  29. x=st[i][j-1],y=st[i+(1<<j-1)][j-1];
  30. st[i][j]=dep[x]<dep[y]?x:y;
  31. }
  32. }
  33. }
  34. ll getdis(int x,int y)
  35. {
  36. ll ret=dis[x]+dis[y];
  37. x=dfn[x],y=dfn[y];
  38. if(x>y) std::swap(x,y);
  39. int d=Log[y+1-x],a=st[x][d],b=st[y-(1<<d)+1][d];
  40. int lca=dep[a]<dep[b]?a:b;
  41. return ret-(dis[lca]<<1);
  42. }
  43. }
  44. struct node
  45. {
  46. int v,w,len;
  47. node(){}
  48. node(int v,int w,int len){this->v=v,this->w=w,this->len=len;}
  49. };
  50. std::vector <node> Edge[N];
  51. int siz[N],del[N],fa[N],si,rt,mi,root,n,m;
  52. void dfs(int now,int fa)
  53. {
  54. siz[now]=1;int mx=0;
  55. for(int v,i=head[now];i;i=Next[i])
  56. {
  57. if((v=to[i])!=fa&&!del[v])
  58. dfs(v,now),siz[now]+=siz[v],mx=mx>siz[v]?mx:siz[v];
  59. }
  60. mx=mx>si-siz[now]?mx:si-siz[now];
  61. if(mi>mx) mi=mx,rt=now;
  62. }
  63. int getroot(int now){mi=N+1;dfs(now,0);return rt;}
  64. void divide(int now)
  65. {
  66. del[now]=1;
  67. for(int v,w,i=head[now];i;i=Next[i])
  68. {
  69. if(!del[w=to[i]])
  70. {
  71. si=siz[w],fa[v=getroot(w)]=now;
  72. Edge[now].push_back(node(v,w,edge[i]));
  73. divide(v);
  74. }
  75. }
  76. }
  77. int d[N],sumd[N];ll sumf[N];
  78. void change(int now,int To,int delta)
  79. {
  80. d[now]+=delta;int las=now;
  81. while(now!=To)
  82. {
  83. sumd[now]+=delta;
  84. sumf[now]+=RMQLCA::getdis(las,fa[now]?fa[now]:now)*delta;
  85. now=fa[now];
  86. }
  87. }
  88. ll cal(int now,int oth,int len)
  89. {
  90. ll ret=1ll*d[now]*len;
  91. for(int v,i=0;i<Edge[now].size();i++)
  92. if((v=Edge[now][i].v)!=oth)
  93. {
  94. ret+=sumf[v];
  95. ret+=1ll*sumd[v]*len;
  96. }
  97. return ret;
  98. }
  99. ll query(int now)
  100. {
  101. ll ret,Ret=0;
  102. for(int v,w,i=0;i<Edge[now].size();i++)
  103. {
  104. if(sumd[v=Edge[now][i].v]<<1>sumd[now])
  105. {
  106. ret=cal(now,v,Edge[now][i].len);
  107. int delta=sumd[now]-sumd[v];
  108. change(w=Edge[now][i].w,now,delta);
  109. ret+=query(v);
  110. change(w,now,-delta);
  111. return ret;
  112. }
  113. Ret+=sumf[v];
  114. }
  115. return Ret;
  116. }
  117. int main()
  118. {
  119. //freopen("data.in","r",stdin);
  120. //freopen("dew.out","w",stdout);
  121. scanf("%d%d",&n,&m);
  122. for(int u,v,w,i=1;i<n;i++)
  123. {
  124. scanf("%d%d%d",&u,&v,&w);
  125. add(u,v,w),add(v,u,w);
  126. }
  127. RMQLCA::init();
  128. mi=N,si=n,root=getroot(1);divide(root);
  129. for(int u,de,i=1;i<=m;i++)
  130. {
  131. scanf("%d%d",&u,&de);
  132. change(u,0,de);
  133. printf("%lld\n",query(root));
  134. }
  135. return 0;
  136. }

2018.12.5

洛谷 P3345 [ZJOI2015]幻想乡战略游戏 解题报告的更多相关文章

  1. 洛谷P3345 [ZJOI2015]幻想乡战略游戏(动态点分治,树的重心,二分查找,Tarjan-LCA,树上差分)

    洛谷题目传送门 动态点分治小白,光是因为思路不清晰就耗费了不知道多少时间去gang这题,所以还是来理理思路吧. 一个树\(T\)里面\(\sum\limits_{v\in T} D_vdist(u,v ...

  2. 洛谷P3345 [ZJOI2015]幻想乡战略游戏 [动态点分治]

    传送门 调了两个小时,终于过了-- 凭啥人家代码80行我180行啊!!! 谁叫你大括号换行 谁叫你写缺省源 思路 显然,补给点所在的位置就是这棵树的带权重心. 考虑size已知时如何找重心:一开始设答 ...

  3. 2018.08.28 洛谷P3345 [ZJOI2015]幻想乡战略游戏(点分树)

    传送门 题目就是要求维护带权重心. 因此破题的关键点自然就是带权重心的性质. 这时发现直接找带权重心是O(n)的,考虑优化方案. 发现点分树的树高是logn级别的,并且对于以u为根的树,带权重心要么就 ...

  4. P3345 [ZJOI2015]幻想乡战略游戏 动态点分治

    \(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...

  5. P3345 [ZJOI2015]幻想乡战略游戏

    传送门 考虑先随便找一个点作为根,然后再慢慢移动根,这样一步步走到最优的点 设 $sum[x]$ 表示节点 $x$ 的子树的军队数,$len(x,y)$ 表示 $x,y$ 之间边的长度 那么对于根节点 ...

  6. BZOJ 3924 / Luogu P3345 [ZJOI2015]幻想乡战略游戏 (动态点分治/点分树)

    题意 树的结构不变,每个点有点权,每一条边有边权,有修改点权的操作,设xxx为树中一点.求∑idist(x,i)∗a[i]\sum_idist(x,i)*a[i]i∑​dist(x,i)∗a[i]的最 ...

  7. AC日记——[ZJOI2015]幻想乡战略游戏 洛谷 P3345

    [ZJOI2015]幻想乡战略游戏 思路: 树剖暴力转移: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...

  8. [ZJOI2015]幻想乡战略游戏——动态点分治

    [ZJOI2015]幻想乡战略游戏 带修改下,边点都带权的重心 随着变动的过程中,一些子树内的点经过会经过一些公共边.考虑能不能对这样的子树一起统计. 把树上贡献分块. 考虑点分治算法 不妨先把题目简 ...

  9. BZOJ3924 ZJOI2015 幻想乡战略游戏 【动态点分治】

    BZOJ3924 ZJOI2015 幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂 ...

随机推荐

  1. vue-cli的安装使用

    通过 npm install vue 安装vue 后: 1.打开cmd 输入 npm install --global vue-cli 全局安装vue-cli脚手架 输入 vue -V 返回vue-c ...

  2. Python和Pycharm的安装

    目录 安装Python 安装Pycharm IDE 破解Pycharm 用Pycharm创建Python工程 安装Python 去Python官网下载Python软件,网址:https://www.p ...

  3. 人脸检测及识别python实现系列(3)——为模型训练准备人脸数据

    人脸检测及识别python实现系列(3)——为模型训练准备人脸数据 机器学习最本质的地方就是基于海量数据统计的学习,说白了,机器学习其实就是在模拟人类儿童的学习行为.举一个简单的例子,成年人并没有主动 ...

  4. TPO 03 - Architecture

    TPO 03 - Architecture Architecture is the art and science of designing structures that[主语是Architectu ...

  5. 互评Alpha版本——基于spec评论作品

    组名:可以低头,但没必要 组长:付佳 组员:张俊余  李文涛  孙赛佳  田良  于洋  刘欣  段晓睿 一.二次元梦之队----I DO 在测评该项目时,我们组索要了该组的apk程序,安装之后我就开 ...

  6. 作业要求20181113-4 Beta阶段第1周/共2周 Scrum立会报告+燃尽图 03

    作业要求:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2385 版本控制:[https://git.coding.net/lglr201 ...

  7. “Hello World!”团队第十三次会议

    今天是我们团队“Hello World!”团队召开的第十三次会议.博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 一.会议时间 2 ...

  8. POJ 2376 (区间问题,贪心)

    题目链接:http://poj.org/problem?id=2376 题目大意:选择一些区间使得能够覆盖1-T中的每一个点,并且区间数最少 题目分析:这道题目很明显可以用贪心法来解决.但题目没有看起 ...

  9. struts2--上传总结(限制大小和类型 非法上传的跳转)

    网上有很多版本,鉴于实践出真知的态度 我自己探索了一番 struts版本:2.3.16 限制大小: struts2默认是2M 所以如果要扩大大小限制,应该先配一个全局struts2最大上限 <c ...

  10. PAT 甲级 1063 Set Similarity

    https://pintia.cn/problem-sets/994805342720868352/problems/994805409175420928 Given two sets of inte ...