题目描述

傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有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<=c<=1000, 0<=|e|<=1000, n<=10^5, Q<=10^5
对于所有数据,这个树上所有点的度数都不超过20
N,Q>=1

输出

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

样例输入

10 5
1 2 1
2 3 1
2 4 1
1 5 1
2 6 1
2 7 1
5 8 1
7 9 1
1 10 1
3 1
2 1
8 1
3 1
4 1

样例输出

0
1
4
5
6


题解

动态点分治

考虑到带权重心一定在当前点到距离与权重总和更小的方向上(没有则当前点为重心),并且这个方向是唯一的,因此可以每次修改都这样移动,把重心找出。

然而直接移动就是直接暴力,需要更优雅的做法。

考虑在子树中移动,可以使用动态点分治的点分树,这样树高只有$\log n$,就可以在每层之间移动重心。

那么只需要想办法求出所有带权点到某个点的距离,并支持修改即可。

由于一个子树以外的点到子树中某点距离可以看作先到根,再从根到该点。所以可以考虑容斥的方法,即用子树中所有点到该点的距离&个数减去子节点的子树中所有点到该点的距离&个数。

然后维护这两个数组即可。由于保证了每个点的度数不超过20,因此每次暴力移动重心,直到所有子节点都比它大为止,此时当前点就是重心。

时间复杂度$O(20n\log^2n)$

#include <cstdio>
#include <algorithm>
#define N 100010
using namespace std;
typedef long long ll;
int head[N] , to[N << 1] , len[N << 1] , next[N << 1] , cnt , log[N << 1] , pos[N] , tot;
int si[N] , mx[N] , sum , root , vis[N] , fa[N] , val[N << 1] , rt , num[N];
ll deep[N] , md[20][N << 1] , va[N] , vb[N];
void add(int x , int y , int z)
{to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x , int fa)
{int i;pos[x] = ++tot , md[0][tot] = deep[x];for(i = head[x] ; i ; i = next[i])if(to[i] != fa)deep[to[i]] = deep[x] + len[i] , dfs(to[i] , x) , md[0][++tot] = deep[x];
}
ll dis(int x , int y)
{ll t = deep[x] + deep[y];x = pos[x] , y = pos[y];if(x > y) swap(x , y);int k = log[y - x + 1];return t - 2 * min(md[k][x] , md[k][y - (1 << k) + 1]);
}
void getroot(int x , int fa)
{int i;si[x] = 1 , mx[x] = 0;for(i = head[x] ; i ; i = next[i])if(!vis[to[i]] && to[i] != fa)getroot(to[i] , x) , si[x] += si[to[i]] , mx[x] = max(mx[x] , si[to[i]]);mx[x] = max(mx[x] , sum - si[x]);if(mx[x] < mx[root]) root = x;
}
void solve(int x)
{int i;vis[x] = 1;for(i = head[x] ; i ; i = next[i])if(!vis[to[i]])sum = si[to[i]] , root = 0 , getroot(to[i] , 0) , fa[root] = x , val[i] = root , solve(root);
}
ll calc(int x)
{int i;ll ans = 0;for(i = x ; i ; i = fa[i]) ans += va[i] + num[i] * dis(x , i);for(i = x ; fa[i] ; i = fa[i]) ans -= vb[i] + num[i] * dis(x , fa[i]);return ans;
}
ll query()
{int x = rt , i , y;ll mn , t;while(1){mn = calc(x) , y = x;for(i = head[x] ; i ; i = next[i])if(val[i] && (t = calc(to[i])) < mn)mn = t , y = val[i];if(x == y) break;x = y;}return mn;
}
int main()
{int n , m , i , j , x , y , z;scanf("%d%d" , &n , &m);for(i = 1 ; i < n ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , add(x , y , z) , add(y , x , z);dfs(1 , 0);for(i = 2 ; i <= tot ; i ++ ) log[i] = log[i >> 1] + 1;for(i = 1 ; (1 << i) <= tot ; i ++ )for(j = 1 ; j <= tot - (1 << i) + 1 ; j ++ )md[i][j] = min(md[i - 1][j] , md[i - 1][j + (1 << (i - 1))]);mx[0] = 1 << 30 , sum = n , getroot(1 , 0) , rt = root , solve(root);while(m -- ){scanf("%d%d" , &x , &y);for(i = x ; i ; i = fa[i]) va[i] += y * dis(x , i) , num[i] += y;for(i = x ; fa[i] ; i = fa[i]) vb[i] += y * dis(x , fa[i]);printf("%lld\n" , query());}return 0;
}

转载于:https://www.cnblogs.com/GXZlegend/p/7465051.html

【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态点分治相关推荐

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

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

  2. Bzoj3924 [Zjoi2015]幻想乡战略游戏

    Time Limit: 100 Sec  Memory Limit: 256 MB Submit: 817  Solved: 376 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏 ...

  3. BZOJ3924 : [Zjoi2015]幻想乡战略游戏

    对于一个点,要求出它到所有点的带权距离和,只需记录下树分治的结构然后查询即可. 修改$O(\log n)$,查询$O(\log n)$. 到所有点带权距离和最小的点显然是这棵树的带权重心. 以1号点为 ...

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

    P3345 [ZJOI2015]幻想乡战略游戏 带修改带权重心 这是经典的树上寻找关键点的题目,我们使用点分治处理这个问题,因为点分治的特性,就相当于在树上二分了.但是这与倍增不同,倍增只是在链上二分 ...

  5. [ZJOI2015] 幻想乡战略游戏——树链剖分

    [ZJOI2015]幻想乡战略游戏 题解 由于所有边的边权是正整数,所以可以发现任何时刻每个点的答案是从最优的点往周围递增的.如果有平台,那么一定是在最优点的连通块那儿. 我们先考虑如何快速求每个点的 ...

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

    二刷这题 在树上寻找带点权和边权的重心,考虑在原树上怎么做: 假设当前答案在根节点 uuu,考虑移动到子节点 vvv,贡献变化是 wu,v∗(tot−2sumv)w_{u,v} * (tot - 2s ...

  7. LG P3345 [ZJOI2015]幻想乡战略游戏(树的带权重心 + 树链剖分+ 动态点分治)

    题目 首先这个题看起来这个最小值不好在动态点分治时维护. (居然)可以转化. 最小值于树的带权重心处取到. 带权带的是点权. 树的带权重心是子树权∗2>=总树权子树权*2>=总树权子树权∗ ...

  8. [zjoi2015]幻想乡战略游戏

    前言 略略略 题目相关 链接 题目大意 给出一棵树,每次修改一个点的权值,维护一个带权重心 啥是带权重心? 设点iii的值为ViV_iVi​我们要选一个点uuu,每个点对应一个值: ∑v=1nVv∗d ...

  9. [ZJOI2015] 幻想乡战略游戏(树链剖分 + 线段树二分 + 带权重心)

    problem luogu-P3345 solution 这是一个带权重心的题,考察动态点分治.点分治?呵,不可能的,这辈子都不可能写点分治 我们重新考虑重心的性质:以这个点为根时,所有子树的大小不会 ...

最新文章

  1. 2021年大数据ELK(二十一):Logstash简介和安装
  2. QOS的qmtoken 1
  3. (转)OpenCV版本的摄像机标定
  4. 2!=5 or 0在python中是否正确-python 中 and or
  5. mysql 5.6 主从同步配置_Mysql 5.6主从同步配置
  6. python与sql连接不上_Python连接不上SQL Server的两种根治思路
  7. Docker安装Redis以及配置Redis环境
  8. 未指定的IO标准导致vivado生成bit文件报错
  9. Qtum研究院:市面上企业级解决方案都有哪些亮点?
  10. 对于JavaScript产生闭包的个人理解
  11. 软件安装 | SolidWorks2016软件安装,SW2010-2016.Activator.GUI.SSQ激活闪退解决办法
  12. 巧用GPSID驱动 快速实现WinCE GPS开发
  13. matlab fisher z变换,科学网—胜过 Fisher z 变换!(2) - 杨正瓴的博文
  14. 月份/星期表(缩写)
  15. App逆向-安卓环境搭建-LineageOS刷机指南
  16. 002 fidder中 Customize Rules打不开却无法下载问题
  17. SpreadJS 表格控件发布V11版本,新增图表及前端PDF导出!
  18. vijos1404 遭遇战
  19. 极路由1S HC5661A 刷入不死u-boot和Openwrt
  20. Intro.js 分步向导插件使用方法 1

热门文章

  1. matlab 2010无法运行程序,matalb r2010a安装后打开出现一系列警告,无法运行,哪位大神帮...
  2. 打印速度快点的打印机_佳能和爱普生打印机哪个好 高性价比打印机介绍【详解】...
  3. mysql query browswer_MySQL数据库新特性之存储过程入门教程
  4. git stash 拉去_git操作命令符
  5. python统计csv行数_对Python 多线程统计所有csv文件的行数方法详解
  6. mysql 选项_mysql常用选项
  7. java comparable接口作用_Java 中 Comparable 接口的意义和用法
  8. java aqs源码_Java-AQS源码详解(细节很多!)
  9. 安装esp8266库_基于ESP8266,DIY低成本智能远程开关灯小装置
  10. 【Mysql】日期、行变列(IF、CASE WHEN THEN)语句总结