「ZJOI2015」幻想乡战略游戏

题目描述

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

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

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

由于幽香需要补给所有的军队,因此幽香总共就要花费为Sigma(Dv*dist(u,v),其中1<=V<=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|单位个军队,说白了就是du←du+e)。数据保证任何时刻每个点上的军队数量都是非负的。

输出格式:

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

输入输出样例

输入样例#1:
复制

  1. 10 5
  2. 1 2 1
  3. 2 3 1
  4. 2 4 1
  5. 1 5 1
  6. 2 6 1
  7. 2 7 1
  8. 5 8 1
  9. 7 9 1
  10. 1 10 1
  11. 3 1
  12. 2 1
  13. 8 1
  14. 3 1
  15. 4 1
输出样例#1:
复制

  1. 0
  2. 1
  3. 4
  4. 5
  5. 6

说明

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

分析

考虑答案的形式,发现跟带权重心非常类似。

假设当前补给站为\(u\),并强制以\(u\)为根,\(v\)为\(u\)的一个子节点,\(sumd_u\)和\(sumd_v\)分别为\(u\)的子树内的\(d\)之和以及\(v\)的子树内的\(d\)之和,\(len(u,v)\)为边\((u,v)\)的长度。

如果将补给站迁移到点\(v\),那么\(v\)的子树内的点到补给站的距离减少了\(len(u,v)\),其他的点到补给站的距离增加了\(len(u,v)\)。也就是说,补给站迁移到点\(v\)时,代价的增量为:

\[len(u,v)\times(sumd_u-sumd_v-sumd_v)
\]

整理一下,得出性质:\(u\)为根,\(v\)为\(u\)的子节点,补给站在\(v\)比\(u\)优,当且仅当:

\[2\times sumd_v>sumd_u
\]

显然满足条件的\(v\)最多只有一个。这时候,如果没有满足条件的\(v\),则\(u\)为最优位置。否则最优位置在\(v\)的子树内

一个一个跳肯定不行,所以考虑使用点分树加速跳跃过程。具体而言,如果发现\(u\rightarrow v\)更优的话,那么就递归计算\(v\)子树中的重心,即\(u\)在点分树上的儿子节点。运用换根DP的知识我们可以维护点分树上面每个节点子树的答案并且做到\(O(\log n)\)查询每个节点换根后的答案。

时间复杂度\(O(n\log n+Q\log^2 n)\)

动态点分治的作用:在点分治的过程中,一般我们面对的问题都是静态的。如果涉及到修改这类的操作,我们就希望找到我们是如何处理到当前的修改点的,换而言之,我们希望记录下点分治的过程,这样可以通过爬点分树等操作消除影响。

  1. #include<bits/stdc++.h>
  2. #define rg register
  3. #define il inline
  4. #define co const
  5. template<class T>il T read(){
  6. rg T data=0,w=1;rg char ch=getchar();
  7. while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
  8. while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
  9. return data*w;
  10. }
  11. template<class T>il T read(rg T&x) {return x=read<T>();}
  12. typedef long long ll;
  13. using namespace std;
  14. typedef pair<int,int> pii;
  15. co int N=2e5+1;
  16. int n,m;
  17. namespace T{ // original tree
  18. vector<pii> e[N];
  19. int lg[N*2],st[N*2][18],dis[N],pos[N],dfn;
  20. void dfs(int u,int fa){
  21. st[pos[u]=++dfn][0]=dis[u];
  22. for(int i=0,v;i<e[u].size();++i){
  23. if((v=e[u][i].first)==fa) continue;
  24. dis[v]=dis[u]+e[u][i].second,dfs(v,u);
  25. st[++dfn][0]=dis[u];
  26. }
  27. }
  28. void init(){
  29. lg[0]=-1;
  30. for(int i=1;i<=n<<1;++i) lg[i]=lg[i>>1]+1;
  31. dfs(1,0),assert(dfn==2*n-1);
  32. for(int j=1;1<<j<=dfn;++j)
  33. for(int i=1;i+(1<<j)-1<=dfn;++i)
  34. st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
  35. }
  36. int get_dis(int u,int v){
  37. if(pos[u]>pos[v]) swap(u,v);
  38. int k=lg[pos[v]-pos[u]+1];
  39. return dis[u]+dis[v]-2*min(st[pos[u]][k],st[pos[v]-(1<<k)+1][k]);
  40. }
  41. }
  42. int vis[N],sum,root,siz[N],f[N],par[N];
  43. ll down[N],up[N],sumd[N];
  44. vector<pii> g[N];
  45. void get_root(int u,int fa){
  46. siz[u]=1,f[u]=0;
  47. for(int i=0,v;i<T::e[u].size();++i){
  48. if(vis[v=T::e[u][i].first]||v==fa) continue;
  49. get_root(v,u);
  50. siz[u]+=siz[v],f[u]=max(f[u],siz[v]);
  51. }
  52. f[u]=max(f[u],sum-siz[u]);
  53. if(f[u]<f[root]) root=u;
  54. }
  55. void work(int u,int fa){
  56. vis[u]=1,par[u]=fa;
  57. for(int i=0,v;i<T::e[u].size();++i){
  58. if(vis[v=T::e[u][i].first]) continue;
  59. sum=siz[v],root=0,get_root(v,0);
  60. g[u].push_back(pii(root,v));
  61. work(root,u);
  62. }
  63. }
  64. void ins(int u,int val){
  65. sumd[u]+=val;
  66. for(int i=u;par[i];i=par[i]){
  67. int dist=T::get_dis(par[i],u);
  68. down[par[i]]+=(ll)dist*val; // underneath ans
  69. up[i]+=(ll)dist*val; // upward transfer
  70. sumd[par[i]]+=val;
  71. }
  72. }
  73. ll calc(int u){
  74. ll ans=down[u];
  75. for(int i=u;par[i];i=par[i]){
  76. int dist=T::get_dis(par[i],u);
  77. ans+=down[par[i]]-up[i]+dist*(sumd[par[i]]-sumd[i]);
  78. }
  79. return ans;
  80. }
  81. ll query(int u){
  82. ll ans=calc(u);
  83. for(int i=0;i<g[u].size();++i)
  84. if(calc(g[u][i].second)<ans)
  85. return query(g[u][i].first);
  86. return ans;
  87. }
  88. int main(){
  89. // freopen("LG3345.in","r",stdin);
  90. read(n),read(m);
  91. for(int i=1,u,v,w;i<n;++i){
  92. read(u),read(v),read(w);
  93. T::e[u].push_back(pii(v,w)),T::e[v].push_back(pii(u,w));
  94. }
  95. T::init();
  96. sum=n,f[0]=n,get_root(1,0);
  97. int tmp=root;work(root,0),root=tmp;
  98. for(int u,e;m--;){
  99. read(u),read(e),ins(u,e);
  100. printf("%lld\n",query(root));
  101. }
  102. return 0;
  103. }

LOJ2135 「ZJOI2015」幻想乡战略游戏的更多相关文章

  1. LOJ #2135. 「ZJOI2015」幻想乡战略游戏

    #2135. 「ZJOI2015」幻想乡战略游戏 链接 分析: 动态点分治,求加权重心,带修改. 考虑如果知道了一个点s,如何求答案,那么首先可以点分治的思想,求每个联通块内所有点到分治中心距离和,然 ...

  2. LOJ #2135. 「ZJOI2015」幻想乡战略游戏(点分树)

    题意 给你一颗 \(n\) 个点的树,每个点的度数不超过 \(20\) ,有 \(q\) 次修改点权的操作. 需要动态维护带权重心,也就是找到一个点 \(v\) 使得 \(\displaystyle ...

  3. loj 2135 「ZJOI2015」幻想乡战略游戏 - 动态点分治

    题目传送门 传送门 题目大意 给定一棵树,初始点权都为0,要求支持: 修改点权 询问带权重心 询问带权重心就在点分树上跑一下就行了.(枚举跳哪个子树更优) 剩下都是基础点分治. 学了一下11-dime ...

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

    唉:-(动态点分治的思想真是复杂...... 先码住,再做几道题再来填坑 PS:接下来的Code因为用了倍增lca所以TLE一部分,但是懒得改成RMQ了...... Code: #include< ...

  5. 洛谷 P3345 [ZJOI2015]幻想乡战略游戏 解题报告

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

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

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

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

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

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

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

  9. 【BZOJ3924】[Zjoi2015]幻想乡战略游戏 动态树分治

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

随机推荐

  1. day19-python的正则表达式2

    正则对象的findall方法 findall(string[, pos[, endpos]])  搜索string,以列表形式返回全部能匹配的子串. import re p1 = re.compile ...

  2. awk计算最大值,最小值,平均值的脚本

    传入至少三个数字参数到脚本awk_file,并计算出最大,最小,平均值.需要判断传入的数字是否足够,否则输出警告信息.平均值保留两位小数. 如执行bash awk_file 3 4 6 5,脚本输出结 ...

  3. oo作业总结(二)

    概述 和前三次作业相比,这几次作业最大的不同是难度的飞跃.遗憾的是在这难度的变化面前,我自己却没有做好充分的准备,错误的低估了作业难度导致给自己带来了很多不必要麻烦和损失.接下来我将对它们进行说明(度 ...

  4. npm webpack vue-cli

    npm.webpack.vue-cli 快速上手版   Node.js   npm 什么是Node.js  以及npm 简单的来说 Node.js 就是运行在服务端的JavaScript,基于Chro ...

  5. 更改centos源为aliyun

    完全参考 http://mirrors.aliyun.com/help/centos?spm=5176.bbsr150321.0.0.d6ykiD 1.备份 mv /etc/yum.repos.d/C ...

  6. vue-router + ElementUI实现NavMenu 导航菜单 选中状态的切换

    elemen-ui官方网站:http://element.eleme.io/#/zh-CN/component/menu 新手小白利用vue+element-ui尝试搭建后台管理系统, 效果是这样的, ...

  7. Vuejs2.0学习(Render函数,createElement,vm.$slots)

    直接来到进阶部分, Render函数 直接来到Render,本来也想跳过,发现后面的路由貌似跟它还有点关联.先来看看Render 1.1 官网一开始就看的挺懵的,不知道讲的是啥,动手试了一下,一开头讲 ...

  8. 接口的鉴权&响应数据解密

    前言: 1.开放的接口为了避免被别人攻击,频繁刷接口,浪费服务器资源,这就涉及到签名(Signature)加密了 2.API 使用签名方法(Signature)对接口进行鉴权(Authenticati ...

  9. git命令学习

    git init:把当前目录变成Git可以管理的仓库git add file:把文件添加到仓库git commit -m "描述语句":把文件提交到仓库git status:该命令 ...

  10. 创建自动化环境(jenkins+tomcat+git+maven,java)

    1.安装jdk 下载1.8以上jdk // 切换到lib cd /usr/lib sudo mkdir jdk cd jdk // 将 jdk拷贝到此目录 // 解压jdk tar -zxvf jdk ...