[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 ...
随机推荐
- LeetCode-391. 完美矩形(使用C语言编译,详解)
链接:https://leetcode-cn.com/problems/perfect-rectangle/description/ 题目 我们有 N 个与坐标轴对齐的矩形, 其中 N > 0, ...
- bug终结者 团队作业第八周
bug终结者 团队作业第八周 本次任务 素材提供及编辑:20162328 蔡文琛 博客修改完善:20162322 朱娅霖 "bug终结者" 宏伟蓝图 UML 手绘底稿 用例图 选项 ...
- NOIP2017 列队
https://www.luogu.org/problemnew/show/P3960 p<=500 50分 模拟 每个人的出队只会影响当前行和最后一列 p<=500,有用的行只有500行 ...
- Vue-cli+Vue.js2.0+Vuex2.0+vue-router+es6+webpack+node.js脚手架搭建和Vue开发实战
Vue.js是一个构建数据驱动的web界面的渐进式框架.在写这边文章时Vue版本分为1.0++和2.0++,这个是基于Vue2.0的项目. Vue-cli是构建单页应用的脚手架,这个可是官方的. Vu ...
- java实现红包的分配算法
个人推测,微信红包在发出的时候已经分配好金额.比如一个10元的红包发给甲乙丙三个人,其实在红包发出去的时候,已经确定了第一个会领取多少,第二个会领取多少金额. 而不是在领取的时候才计算的.下面贴出实现 ...
- python使用tesseract-ocr完成验证码识别(模型训练和使用部分)
一.Tesseract训练 大体流程为:安装jTessBoxEditor -> 获取样本文件 -> Merge样本文件 –> 生成BOX文件 -> 定义字符配置文件 -> ...
- SpringCloud的DataRest(三)
一.进阶配置定义 二.定制显示内容和控制方法使用 1.控制显示的内容 如果想让输出显示的数据始终按我们定义的格式显示: 配置之后返回的JSON数据会按照ListApp定义的数据格式进行输出 2.屏蔽自 ...
- Groovy入门(2-2)Groovy的eclipse插件安装
1.安装eclipse插件 启动eclipse,点击help -> Install New Software... 在弹出的窗口中点击:Add... Groovy插件的地址:http://dis ...
- 【52ABP实战教程】0.2-- VSTS中的账号迁移到东亚
需求从哪里来! VSTS的全称是Visual Studio Team Services. 在上一篇的文章中已经给大家说了VSTS之前是没有香港节点.大家的访问速度回比较慢.但是11月10号微软就宣布开 ...
- EasyUI中datagrid的基本用法
EasyUI中datagrid是最常用的一个控件了,现在整理一下datagrid的基本语法,先展示下页面效果吧,如下图