[ZJOI 2015]幻想乡战略游戏
Description
傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点u上,并且空地v上有dv个单位的军队,那么幽香每天就要花费dv×dist(u,v)的金钱来补给这些军队。由于幽香需要补给所有的军队,因此幽香总共就要花费为Sigma(Dv*dist(u,v),其中1<=V<=N)的代价。其中dist(u,v)表示u个v在树上的距离(唯一路径的权和)。 因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。
Input
Output
对于幽香的每个操作,输出操作完成以后,每天的最小花费,也即如果幽香选择最优的补给点进行补给时的花费。
Sample Input
1 2 1
2 3 1
2 4 1
1 5 1
2 61
2 7 1
5 8 1
7 91
1 10 1
3 1
2 1
8 1
3 1
4 1
Sample Output
1
4
5
6
题解
其实和[HNOI 2015]开店的动态点分统计答案的方法类似,不再赘述。
这里主要讲如何找到“带权重心”。
我们每次从点分的根开始遍历与它相邻的所有点,统计出他们的答案,值得肯定的是这些值只会存在两种情况:
1. 相邻的所有值都大于这个点的答案,显然这个点就是要求的点;
2. 相邻的点只有一个的值,小于这个点统计出的答案,就直接向这棵更小的子树走,注意是走到“分治树”的下一个重心,继续操作。
//It is made by Awson on 2018.1.9
#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define lowbit(x) ((x)&(-(x)))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
using namespace std;
const int N = 1e5;
const int INF = ~0u>>;
void read(int &x) {
char ch; bool flag = ;
for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || ); ch = getchar());
for (x = ; isdigit(ch); x = (x<<)+(x<<)+ch-, ch = getchar());
x *= -*flag;
} int n, q, u, v, c, fa[N+], G;
LL sum[N+], dis1[N+], dis2[N+];
struct tt {
int to, next, cost;
}G1edge[(N<<)+], G2edge[N+];
int G1path[N+], G1top, G2path[N+], G2top;
void G1add(int u, int v, int c) {
G1edge[++G1top].to = v, G1edge[G1top].cost = c, G1edge[G1top].next = G1path[u], G1path[u] = G1top;
}
void G2add(int u, int v, int c) {
G2edge[++G2top].to = v, G2edge[G2top].cost = c, G2edge[G2top].next = G2path[u], G2path[u] = G2top;
}
namespace LCA {
int lim, bin[], dfn[N+], tim, logn[(N<<)+];
LL f[(N<<)+][];
void dfs(int o, LL cost, int father) {
f[dfn[o] = ++tim][] = cost;
for (int i = G1path[o]; i; i = G1edge[i].next)
if (G1edge[i].to != father) dfs(G1edge[i].to, cost+G1edge[i].cost, o), f[++tim][] = cost;
}
LL query(int x, int y) {
if (dfn[x] > dfn[y]) Swap(x, y);
int lim = logn[dfn[y]-dfn[x]+];
return Min(f[dfn[x]][lim], f[dfn[y]-bin[lim]+][lim]);
}
LL dist(int x, int y) {return f[dfn[x]][]+f[dfn[y]][]-(query(x, y)<<); }
void main() {
lim = log(n<<)/log(); bin[] = ; for (int i = ; i <= ; i++) bin[i] = bin[i-]<<;
logn[] = -; for (int i = ; i <= (n<<); i++) logn[i] = logn[i>>]+;
dfs(, , );
for (int t = ; t <= lim; t++) for (int i = ; i+bin[t]- <= (n<<); i++) f[i][t] = Min(f[i][t-], f[i+bin[t-]][t-]);
}
}
namespace Point_divide {
int size[N+], mx[N+], vis[N+], minsize, root;
void get_size(int o, int fa) {
size[o] = , mx[o] = ;
for (int i = G1path[o]; i; i = G1edge[i].next)
if (G1edge[i].to != fa && !vis[G1edge[i].to]) {
get_size(G1edge[i].to, o);
size[o] += size[G1edge[i].to];
if (size[G1edge[i].to] > mx[o]) mx[o] = size[G1edge[i].to];
}
}
void get_root(int o, int pa, int fa) {
mx[o] = Max(mx[o], size[pa]-size[o]);
if (minsize > mx[o]) minsize = mx[o], root = o;
for (int i = G1path[o]; i; i = G1edge[i].next)
if (G1edge[i].to != fa && !vis[G1edge[i].to]) get_root(G1edge[i].to, pa, o);
}
void work(int o, int pa) {
minsize = INF; get_size(o, ), get_root(o, o, );
vis[root] = ; fa[root] = pa; int rt = root; G2add(pa, root, o);
for (int i = G1path[root]; i; i = G1edge[i].next)
if (!vis[G1edge[i].to]) work(G1edge[i].to, rt);
G = rt;
}
void main() {work(, ); }
} void update(int o, int c) {
for (int x = o; x; x = fa[x]) {
sum[x] += c;
dis1[x] += (LL)c*LCA::dist(x, o);
if (fa[x]) dis2[x] += (LL)c*LCA::dist(fa[x], o);
}
}
LL get_ans(int o) {
LL ans = ;
for (int x = o; x; x = fa[x]) {
ans += dis1[x]+sum[x]*LCA::dist(x, o);
if (fa[x]) ans -= sum[x]*LCA::dist(fa[x], o)+dis2[x];
}
return ans;
}
LL query(int o) {
LL ans = get_ans(o);
for (int i = G2path[o]; i; i = G2edge[i].next) {
LL tmp = get_ans(G2edge[i].cost);
if (tmp < ans) return query(G2edge[i].to);
}
return ans;
}
void work() {
read(n), read(q);
for (int i = ; i < n; i++) read(u), read(v), read(c), G1add(u, v, c), G1add(v, u, c);
LCA::main(); Point_divide::main();
while (q--) {
read(u), read(c); update(u, c);
printf("%lld\n", query(G));
}
}
int main() {
work();
return ;
}
[ZJOI 2015]幻想乡战略游戏的更多相关文章
- ZJOI 2015 幻想乡战略游戏(动态点分治)
题意 https://loj.ac/problem/2135 思路 首先要明确一点,答案分布是有单调性的.什么意思呢?假设我们的答案在 \(u\) 节点,\((u,v)\) 之间有一条边且 \(u\) ...
- 解题:ZJOI 2015 幻想乡战略游戏
题面 神**所有点都爆int,我还以为我写出什么大锅了,不开long long见祖宗... 动态点分治利用点分树树高不超过log的性质,我们对每个点维护一个子树和,一个点分树子树和,一个点分树上父亲的 ...
- 【BZOJ3924】幻想乡战略游戏(动态点分治)
[BZOJ3924]幻想乡战略游戏(动态点分治) 题面 权限题...(穷死我了) 洛谷 题解 考虑不修改 发现一个贪心的做法 假设当前放在当前位置 如果它有一个子树的兵的总数大于总数的一半 那么,放到 ...
- LOJ2135 「ZJOI2015」幻想乡战略游戏
题意 题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和 ...
- LOJ #2135. 「ZJOI2015」幻想乡战略游戏
#2135. 「ZJOI2015」幻想乡战略游戏 链接 分析: 动态点分治,求加权重心,带修改. 考虑如果知道了一个点s,如何求答案,那么首先可以点分治的思想,求每个联通块内所有点到分治中心距离和,然 ...
- 洛谷 P3345 [ZJOI2015]幻想乡战略游戏 解题报告
P3345 [ZJOI2015]幻想乡战略游戏 题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做 ...
- [ZJOI2015]幻想乡战略游戏——动态点分治
[ZJOI2015]幻想乡战略游戏 带修改下,边点都带权的重心 随着变动的过程中,一些子树内的点经过会经过一些公共边.考虑能不能对这样的子树一起统计. 把树上贡献分块. 考虑点分治算法 不妨先把题目简 ...
- BZOJ3924 ZJOI2015 幻想乡战略游戏 【动态点分治】
BZOJ3924 ZJOI2015 幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂 ...
- AC日记——[ZJOI2015]幻想乡战略游戏 洛谷 P3345
[ZJOI2015]幻想乡战略游戏 思路: 树剖暴力转移: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...
随机推荐
- Elasticsearch安装详解
本文只介绍在windows上的安装和配置,其他安装和配置请参见官方文档 ES在windows上安装需下载zip安装包,解压后bin目录下有个 elasticsearch-service.bat 文件. ...
- 用jQuery.delegate()将事件绑定在父元素上面
1.先看看官方的示例: <html> <head> <script type="text/javascript" src="/jquery/ ...
- 4c语言的第0次作业
1.你认为大学的学习生活.同学关系.师生关系应该是怎样? 我认为大学的学习生活应该是充实有意义的,有对学习的激情又有与伙伴相知的愉悦. 我认为同学关系应该是互相尊重,互相学习,坦诚相待. 我认为师生关 ...
- Beta冲刺 第一天
Beta冲刺 第一天 1. 昨天的困难 由于今天还是第一天,所以暂时没有昨天的困难. 2. 今天解决的进度 潘伟靖: 对代码进行了review 1.将某些硬编码改为软编码 2.合并了一些方法,简化代码 ...
- 冲刺每日报告--Day1
敏捷冲刺每日报告--Day1 情况简介 由于李世钰同学出差了,周六才能回来.所以我们只能先写爬虫,封装代码提供接口等他回来调用. 任务进度 赵坤:编写了基本爬虫代码,目前能在国内有版权的B站.爱奇艺中 ...
- MariaDB/MySQL存储过程和函数
本文目录:1.创建存储过程.函数 1.1 存储过程的IN.OUT和INOUT2.修改和删除存储过程.函数3.查看存储过程.函数信息 在MySQL/MariaDB中,存储过程(stored proced ...
- typescript简介
微软作为编译器狂魔一直有一个心病,就是改良JavaScript这种语法超级烂又很多人用的编程语言,于是TypeScript诞生了 先做个对比吧: TS JS 语法严谨性 严谨 宽松 静态性 静态 ...
- leetcode题解 6.ZigZag Conversion
6.ZigZag Conversion 题目: The string "PAYPALISHIRING" is written in a zigzag pattern on a gi ...
- HashMap 的底层原理
1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端. 数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O(1 ...
- System Rules 更好的测试
1:编写测试事例时候,我们要从控制台拿到数据与断言进行对比,通常要编写jdk 标准输出的屏蔽控制器.文章标题的包,能够更好的为我们进行工作. package demo2; import static ...