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

题目传送门

  传送门

题目大意

  给定一棵树,初始点权都为0,要求支持:

  • 修改点权
  • 询问带权重心

  询问带权重心就在点分树上跑一下就行了。(枚举跳哪个子树更优)

  剩下都是基础点分治。

  学了一下11-dimensional的2.2k动态点分治,然后写抄出来只有1.9k???

Code

/**
 * loj
 * Problem#2135
 * Accepted
 * Time: 4492ms
 * Memory: 28404k
 */
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;

typedef class Edge {
	public:
		int ed, w, ctr;

		Edge() {	}
		Edge(int ed, int w) : ed(ed), w(w), ctr(-1) {	}
} Edge;

#define ll long long

const int N = 1e5 + 5;

int n, m;
boolean ban[N];
vector<Edge> G[N];
ll d[N][19], c[N], f[N];
int layer[N], faG[N], sz[N];

int get_sz(int p, int fa) { // calc size
	sz[p] = 1;
	for (auto& E : G[p])
		sz[p] += ((E.ed == fa || ban[E.ed]) ? (0) : (get_sz(E.ed, p)));
	return sz[p];
}

int get_G(int p, int fa, int hs) {
	for (auto& E : G[p]) {
		if ((E.ed ^ fa) && !ban[E.ed] && sz[E.ed] > hs) {
			return get_G(E.ed, p, hs);
		}
	}
	return p;
}

void prepare_dist(int p, int fa, int lay) {
	for (auto& E : G[p]) {
		if ((E.ed ^ fa) && !ban[E.ed]) {
			d[E.ed][lay] = d[p][lay] + E.w;
			prepare_dist(E.ed, p, lay);
		}
	}
}

int dividing(int x, int _faG, int lay) {
	int G = get_G(x, 0, get_sz(x, 0) >> 1);
	faG[G] = _faG, ban[G] = true;
	d[G][lay] = 0, layer[G] = lay;
	prepare_dist(G, 0, lay);
	for (auto& E : ::G[G]) {
		if (!ban[E.ed]) {
			E.ctr = dividing(E.ed, G, lay + 1);
		}
	}
	return G;
}

void update(int u, int v) {
	for (int p = u ; p; p = faG[p]) {
		f[p] += (d[u][layer[p]] - d[u][layer[p] - 1]) * v;
		c[p] += v;
	}
}

ll calc(int u) {
	ll ret = 0, lc = 0;
	for (int p = u; p; lc = c[p], p = faG[p]) {
		ret += f[p] + (c[p] - lc) * d[u][layer[p]];
	}
	return ret;
}

ll solve(int u) {
	ll ans = calc(u);
	for (auto& E : G[u]) {
		if (~E.ctr && calc(E.ed) < ans) {
			return solve(E.ctr);
		}
	}
	return ans;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1, u, v, w; i < n; i++) {
		scanf("%d%d%d", &u, &v, &w);
		G[u].emplace_back(v, w);
		G[v].emplace_back(u, w);
	}
	int ctr = dividing(1, 0, 1), u, e;
	while (m--) {
		scanf("%d%d", &u, &e);
		update(u, e);
		printf("%lld\n", solve(ctr));
	}
	return 0;
}

原文地址:https://www.cnblogs.com/yyf0309/p/10799826.html

时间: 2024-08-29 14:18:13

loj 2135 「ZJOI2015」幻想乡战略游戏 - 动态点分治的相关文章

BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治

题目大意:给定一棵树,每个点有一个点权,多次改变某个点的点权,多次查询带权重心到所有点的带权距离之和 此生无悔入东方,来世愿生幻想乡 首先我们考虑如何计算一个点到所有点的带权距离之和且支持修改 用动态树分治就好了嘛... 每个点记录子树中带权距离之和,以及权值之和,再在每个子树中记录一个需要减掉的版本 然后一直向上扫到根就能统计了 ↑这段话面对会写动态树分治的人,不会的先去切捉迷藏吧 然后就好搞了... 对于分治结构的每一个点,我们枚举它的出边 如果某条出边连向的点的距离之和小于当前点,那么答案

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

题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来.在游戏中,幽香可能在空地上增加或者减少一些军队.同时,幽香可以在一个空地上放置一个补给站. 如果补给站在点u上,并

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

题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来. 在游戏中,幽香可能在空地上增加或者减少一些军队.同时,幽香可以在一个空地上放置一个补给站. 如果补给站在点u上,

BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)

这种动态点分治嘛,GDKOI时听打到了,也有同学讲到了,所以印象比较深刻也就想出来了,然后就在实现方面卡了好久= = 不得不说CLJ说得真的太简单了,实现方面根本没提. 首先我们可以先用树分治构建出这棵树的分治树,也就是把这棵树的重心作为根节点然后子树为他的子树的重心这样递归下去,然后每个节点存的是其子树的信息. 对于每个节点我们保存这个子树的dv的总和已经把该节点作为点的答案值 这样对于修改能在log n的时间内解决 寻找答案的时候,我们可以发现,如果现在节点的子树dv和*2大于总节点,那么向

[ZJOI2015]幻想乡战略游戏 - 动态点分治

先考虑无修要怎么操作. 发现在无修的情况下,我们可以用一个换根\(dp\)解决. 那么带修改的情况要怎么办呢? 每次修改重新\(dp\)一遍不就行了(雾. 好的,让我们先来敲一个\(O(N^2)\)的\(dp\). #include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll ty() { char ch = getchar(); ll x = 0, f = 1; while (ch < '0'

bzoj3924 [Zjoi2015]幻想乡战略游戏 点分树,动态点分

[BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来.在游戏中,幽香可能在空地上增加或者减少一些军

[ZJOI2015]幻想乡战略游戏 解题报告 (动态点分治)

[ZJOI2015]幻想乡战略游戏 题意 有一棵大小为 \(n\) 的带权树, 每个点有一个权值, 权值可以修改 \(q\) 次, 找出一个补给点 \(x\) , 使得 \(\sum_{u \in V} val[u] \times dis(x,u)\) 最小, 并求出这个最小值. 一句话 : 求带权重心 (zsy说的) 附加条件 : 树中所有点的度数不超过 \(20\). 思路 一道你以为复杂度过不了, 但其实是过得了的题. 首先, 我们假定先选了一个点 \(u\) 作为补给点, 我们可以算出它

【BZOJ3924】幻想乡战略游戏(动态点分治)

[BZOJ3924]幻想乡战略游戏(动态点分治) 题面 权限题...(穷死我了) 洛谷 题解 考虑不修改 发现一个贪心的做法 假设当前放在当前位置 如果它有一个子树的兵的总数大于总数的一半 那么,放到那个子树的根节点上一定最优 那么,现在是动态修改 考虑动态点分治 在每个点上维护子树的兵的总数 子树到上一层父亲节点 向上走产生的贡献的总和 以及接收到子节点的贡献的总和 那么,就可以计算当前点产生的贡献 于是,从分治树根开始向下贪心即可 #include<iostream> #include&l

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

对于一个点,要求出它到所有点的带权距离和,只需记录下树分治的结构然后查询即可. 修改$O(\log n)$,查询$O(\log n)$. 到所有点带权距离和最小的点显然是这棵树的带权重心. 以1号点为根,考虑一条从父亲x到孩子y的边: 若y子树内权值和>=总权值和-y子树内权值和,即2*y子树内权值和>=总权值和,则重心在y的子树里,否则不在. 所以重心一定是深度最大的满足2*子树内权值和>=总权值和的点. 可以发现重心及其祖先都满足2*子树内权值和>=总权值和,而这些点在DFS序