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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章