BZOJ3924【树链剖分】【线段树】

每次暴力转移重心.

/* I will wait for you */

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <string>
#define make(a,b) make_pair(a,b)
#define fi first
#define se second

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef map<int, int> mii;

const int maxn = 100010;
const int maxm = 1010;
const int maxs = 26;
const int inf = 0x3f3f3f3f;
const int P = 1000000007;
const double error = 1e-9;

inline ll read()
{
	ll x = 0, f = 1; char ch = getchar();
	while (ch > '9' || ch < '0' )
		f = (ch == '-' ? -1 : 1), ch = getchar();
	while (ch <= '9' && ch >= '0')
		x = x * 10 + ch - '0', ch = getchar();
	return f * x;
}

struct edge
{
	int v, w, next;
} e[2 * maxn];

struct node
{
	int l, r, sum;
} t[4 * maxn];

int n, m, cnt, dfn, root = 1, per[maxn], fa[maxn], dist[maxn],
    mx[maxn], deep[maxn], size[maxn], pos[maxn], head[maxn];

ll ans, tot;

void insert(int u, int v, int w)
{
	e[cnt] = (edge) {v, w, head[u]}, head[u] = cnt++;
	e[cnt] = (edge) {u, w, head[v]}, head[v] = cnt++;
}

void dfs1(int u)
{
	size[u] = 1;

	for (int i = head[u]; i != -1; i = e[i].next) {
		int v = e[i].v;
		if (v != fa[u]) {
			fa[v] = u, deep[v] = deep[u] + 1;
			dist[v] = dist[u] + e[i].w;
			dfs1(v), size[u] += size[v];

			if (size[v] > size[mx[u]])
				mx[u] = v;
		}
	}
}

void dfs2(int u, int p)
{
	pos[u] = ++dfn, per[u] = p;

	if (mx[u])
		dfs2(mx[u], p);

	for (int i = head[u]; i != -1; i = e[i].next) {
		int v = e[i].v;
		if (v != fa[u] && v != mx[u])
			dfs2(v, v);
	}
}

int lca(int u, int v)
{
	while (per[u] != per[v]) {
		int pu = per[u], pv = per[v];
		if (deep[pu] < deep[pv])
			swap(u, v), swap(pu, pv);
		u = fa[pu];
	}

	if (deep[u] < deep[v])
		swap(u, v);
	return v;
}

int dis(int u, int v)
{
	int p = lca(u, v);
	return dist[u] + dist[v] - 2 * dist[p];
}

void build(int u, int l, int r)
{
	t[u].l = l, t[u].r = r;
	
	if (l != r) {
		int mid = (l + r) / 2;

		build(2 * u, l, mid);
		build(2 * u + 1, mid + 1, r);
	}
}

void change(int u, int x, int val)
{
	int l = t[u].l, r = t[u].r;

	if (l == r)
		t[u].sum += val;

	else {
		int mid = (l + r) / 2;

		if (x <= mid)
			change(2 * u, x, val);
		else 
			change(2 * u + 1, x, val);

		t[u].sum = t[2 * u].sum + t[2 * u + 1].sum;
	}
}

int query(int u, int x, int y)
{
	int l = t[u].l, r = t[u].r;

	if (l >= x && r <= y)
		return t[u].sum;

	else {
		int mid = (l + r) / 2, res = 0;

		if (x <= mid)
			res += query(2 * u, x, y);
		if (y > mid)
			res += query(2 * u + 1, x, y);

		return res;
	}
}

ll solve(int u, int w)
{
	int t1, t2;

	if (u == fa[root]) {
		t1 = query(1, pos[root], pos[root] + size[root] - 1);
		t2 = tot - t1;
	}

	else {
		t2 = query(1, pos[u], pos[u] + size[u] -1);
		t1 = tot - t2;
	}

	return ans + (ll) (t1 - t2) * w;
}

void move()
{
	ll tmp = (ll) inf * inf, t,  pos;

	for (int i = head[root]; i != -1; i = e[i].next) {
		int v = e[i].v; t = solve(v, e[i].w);
		if (t < tmp)
			tmp = t, pos = v;
	}

	if (tmp < ans)
		ans = tmp, root = pos, move();
}	

int main()
{
	n = read(), m = read(), build(1, 1, n);

	memset(head, -1, sizeof head);
	for (int i = 1; i < n; i++) {
		int u = read(), v = read(), w = read();
		insert(u, v, w);
	}

	dfs1(1), dfs2(1, 1);

	for (int i = 1; i <= m; i++) {
		int u = read(), w = read();

		ans += (ll) w * dis(u, root);
		tot += w, change(1, pos[u], w);

		move(), printf("%lld\n", ans);
	}

	return 0;
}

你可能感兴趣的:(BZOJ3924【树链剖分】【线段树】)