[LOJ#2497]. 「PA 2017」Banany

[LOJ#2497]. 「PA 2017」Banany

题意

非常简单的题意

给你一颗树,然后边有边权,点有点权,然后每次你在一个点,求到另外一个点的最大利润,强制在线,动态修改边权和点权。

利润是

\[p_i-\sum_{e\in \text{path}} e_i \]

题解

码力大幅度退化,一眼秒掉,然后打俩小时。这种树上路径问题,一看就是点分治。而且修改,那就很动态对吧。

我们考虑建立点分树,对于每个分治中心及其区域,我们计算这个中心到区域里每个点的利润。那么我们不带修改的询问就可以直接暴力跳点分树完成了。就是从 \(x\) 暴力跳父亲即可。

考虑如何修改,修改点权的话,只要从这个点到他的所有祖先的分治区域修改即可,对于修改边权,对于每次分治影响了一个子树,那么很明显就是dfs序问题,我们只要对于每个分治区域维护一颗线段树,每次区间修改即可。

老久不用 std::function<()> 了,写错了好多,我是屑。

#include <bits/stdc++.h>
const int MOD = 998244353, INF = 0x3f3f3f3f, N = 1e5 + 10, LOG = 20;
const double eps = 1e-9, alpha = 0.7, Pi = acos(-1);
using std::make_pair;
using std::pair;
using std::tuple;
using std::make_tuple;
template<typename T>inline T read() { T x = 0; bool f = 0; char ch = getchar(); while (!isdigit(ch)) { f = ch == '-'; ch = getchar(); } while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } return f ? -x : x; }
template<typename T>inline T max(const T &x, const T &y) { return x > y ? x : y; }
template<typename T>inline T min(const T &x, const T &y) { return x < y ? x : y; }
template<typename T>inline T abs(const T &x) { return x > 0 ? x : -x; }
inline int Mod(int x, const int mod = MOD) { if (x >= mod) { return x - mod; } else if (x < 0) { return x + mod; } else { return x; } }
template<typename T>
struct stack { int top; T vals[N]; bool empty() { return !top; } void push(T x) { vals[++top] = x; } void pop() { if (top > 0) { --top; } return; } void clear() { top = 0; } T TOP() { return vals[top]; } };
inline int ksm(int x, int y, int mod = MOD) { int ret = 1; for ( ; y; y /= 2, x = 1LL * x * x % mod) { if (y & 1) { ret = 1LL * ret * x % mod; } } return ret; }
inline int ksc(int x, int y, int mod = MOD) { int ret = 0; for ( ; y; y /= 2, x = Mod(x + x)) { if (y & 1) { ret = Mod(ret + x); } } return ret; }
struct graph { int cnt, h[N]; pair<int, int> edge[N * 2]; void add_edge(int x, int y) { edge[cnt].first = y; edge[cnt].second = h[x]; h[x] = cnt++; } void clear() { memset(h, -1, sizeof h); cnt = 0; } };
inline int sign(double x) { if (fabs(x) < eps) { return 0; } else if (x < 0) { return -1; } else { return 1; } }
template<typename T>
struct BIT { int limit; T vals[N]; void resize(int n) { limit = n; } void add(int x, T y) { for ( ; x <= limit; x += x & -x) { vals[x] += y; } } T sum(int x) { T ret = 0; for ( ; x; x -= x & -x) { ret = ret + vals[x]; } return ret; } };
inline void flush() { std::cout << std::endl; }
template<typename T>
inline void readin(T *elem, int size) { for (int i = 1; i <= size; ++i) { std::cin >> elem[i]; } }
template<typename T>
inline T sqr(const T &x) { return x * x; }
struct Complex {
double r, v;
Complex(double X = 0, double Y = 0) : r(X), v(Y) {}
friend Complex operator + (const Complex &a, const Complex &b) { return Complex(a.r + b.r, a.v + b.v); }
friend Complex operator - (const Complex &a, const Complex &b) { return Complex(a.r - b.r, a.v - b.v); }
friend Complex operator * (const Complex &a, const Complex &b) { return Complex(a.r * b.r - a.v * b.v, a.r * b.v + b.r * a.v); }
friend Complex operator / (const Complex &a, const double &b) { return Complex(a.r / b, a.v / b); }
friend Complex operator / (const Complex &a, const Complex &b) { return a * (Complex(b.r, -b.v) / (sqr(b.r) + sqr(b.v))); }
};
inline int GetLim(int x) { return x ? 1 << (32 - __builtin_clz(x)) : 1; }
using std::set;
using std::map;
using std::vector;
using std::ios;
using std::cin;
using std::cout;
using std::endl;
using std::queue;
using std::cerr;
#define space ' '
#define enter '\n'
#define orz_1
#define orz_2
int n, q, vis[N], sz[N][LOG], depth[N], fa[N][LOG], dfn[N][LOG], segrt[N], ls[N * LOG * 2], rs[N * 2 * LOG];
long long val[N], tag[N * 2 * LOG], w[N];
struct Seg_Node {
	int id, rt, pos;
	long long val;
} qs[N * LOG * 2];
vector<pair<int, long long>> edge[N];
vector<int> id[N];
map<pair<int, int>, long long> mp;
Seg_Node operator + (Seg_Node a, Seg_Node b) {
	if (a.rt == -1) {
		return b;
	}
	else if (b.rt == -1) {
		return a;
	}
	else if (a.val != b.val) {
		return a.val > b.val ? a : b;
	}
	else {
		return id[a.rt][a.pos - 1] < id[b.rt][b.pos - 1] ? a : b;
	}
}
int main() {
//#ifdef siriehn_nx
//freopen("ban1.in", "r", stdin);
ios::sync_with_stdio(0);
cin.tie(0);
cout << std::fixed << std::setprecision(10);
//#endif
cin >> n >> q;
for (int i = 1; i <= n; ++i) {
	cin >> w[i];
}
int x, y;
long long eval;
for (int i = 1; i < n; ++i) {
	cin >> x >> y >> eval;
	edge[x].emplace_back(y, eval);
	edge[y].emplace_back(x, eval);
	if (x > y) {
		std::swap(x, y);
	}
	mp[make_pair(x, y)] = eval;
}
std::function<int(int,int, int, int)> get_root = [&] (int u, int d, int fa, int S) {
	int mx = 0;
	for (auto &j: edge[u]) {
		if (!vis[j.first] && j.first != fa) {
			int root = get_root(j.first, d, u, S);
			if (root) {
				return root;
			}
			mx = max(mx, sz[j.first][d]);
		}
	}
	return max(mx, S - sz[u][d]) <= S / 2 ? u : 0;
};
int dfc = 0, tot = 0;
std::function<void(int, int, int, int)> dfs_sz = [&] (int u, int d, int par, int rt) {
	sz[u][d] = 1;
	fa[u][d] = rt;
	dfn[u][d] = ++dfc;
	id[rt].push_back(u);
	for (auto &j: edge[u]) {
		if (j.first != par && !vis[j.first]) {
			dfs_sz(j.first, d, u, rt);
			sz[u][d] += sz[j.first][d];
		}
	}
};
std::function<void(int, long long, int)> get_dis = [&] (int u, long long path, int fa) {
	val[u] = w[u] - path;
	if (u == 100) {
		cerr << val[u] << '\n';
	}
	for (auto &j:edge[u]) {
		if (!vis[j.first] && j.first != fa) {
			get_dis(j.first, path + j.second, u);
		}
	}
};
std::function<int(int, int, int)> build = [&] (int l, int r, int rt) {
	int Node_id = ++tot;
	if (l == r) {
		qs[Node_id].val = val[id[rt][l - 1]];
		qs[Node_id].rt = rt;
		qs[Node_id].pos = l;
		return Node_id;
	}
	else {
		int mid = (l + r) / 2;
		qs[Node_id] = qs[ls[Node_id] = build(l, mid, rt)] + qs[rs[Node_id] = build(mid + 1, r, rt)];
		return Node_id;
	}
};
std::function<void(int, int)> solve = [&] (int u, int d) {
	vis[u] = 1;
	depth[u] = d;
	dfc = 0;
	dfs_sz(u, d, 0, u);
//	cout << u << '\n';
//	cout.flush();
	get_dis(u, 0, 0);
	segrt[u] = build(1, sz[u][d], u);
	for (auto &j: edge[u]) {
		if (!vis[j.first]) {
			solve(get_root(j.first, d, 0, sz[j.first][d]), d + 1);
		}
	}
};
dfs_sz(1, 0, 0, 1);
solve(get_root(1, 0, 0, n), 0);
std::function<void(int)> down = [&] (int u) {
	qs[ls[u]].val += tag[u];
	tag[ls[u]] += tag[u];
	qs[rs[u]].val += tag[u];
	tag[rs[u]] += tag[u];
	tag[u] = 0;
	return;
};
std::function<void(int, int, int, int, int, long long)> modify = [&] (int u, int l, int r, int ql, int qr, long long val) {
	if (ql <= l && r <= qr) {
		qs[u].val += val;
		tag[u] += val;
		return;
	}
	down(u);
	int mid = (l + r) / 2;
	if (ql <= mid) {
		modify(ls[u], l, mid, ql, qr, val);
	}
	if (mid < qr) {
		modify(rs[u], mid + 1, r, ql, qr, val);
	}
	qs[u] = qs[ls[u]] + qs[rs[u]];
	return;
};
int pos = 1, opt;
long long z;
qs[0].rt = -1;
for (int cases = 1; cases <= q; ++cases) {
	cin >> opt;
	if (opt == 1) {
		cin >> x >> z;
		for (int i = x; ; i = fa[i][depth[i] - 1]) {
			modify(segrt[i], 1, sz[i][depth[i]], dfn[x][depth[i]], dfn[x][depth[i]], z - w[x]);
			if (!depth[i]) {
				break;
			}
		}
		w[x] = z;
	}
	else {
		cin >> x >> y >> z;
		if (x > y) {
			std::swap(x, y);
		}
		long long delta = z - mp[make_pair(x, y)];
		mp[make_pair(x, y)] = z;
		if (depth[x] < depth[y]) {
			std::swap(x, y);
		}
		for (int i = y; ; i = fa[i][depth[i] - 1]) {
			if (dfn[x][depth[i]] < dfn[y][depth[i]]) {
				std::swap(x, y);
			}
			modify(segrt[i], 1, sz[i][depth[i]], dfn[x][depth[i]], dfn[x][depth[i]] + sz[x][depth[i]] - 1, -delta);
			if (!depth[i]) {
				break;
			}
		}
	}
	Seg_Node ans = qs[0];
std::function<Seg_Node(int, int, int, int, int)> query = [&] (int u, int l, int r, int ql, int qr) {
	if (ql > qr) {
		return qs[0];
	}
	if (ql <= l && r <= qr) {
		return qs[u];
	}
	down(u);
	int mid = (l + r) / 2;
	if (qr <= mid) {
		return query(ls[u], l, mid, ql, qr);
	}
	else if (mid < ql) {
		return query(rs[u], mid + 1, r, ql, qr);
	}
	else {
		return query(ls[u], l, mid, ql, qr) + query(rs[u], mid + 1, r, ql, qr);
	}
};
	for (int i = pos; ; i = fa[i][depth[i] - 1]) {
		Seg_Node tmp = query(segrt[i], 1, sz[i][depth[i]], 1, dfn[pos][depth[i]] - 1) + query(segrt[i], 1, sz[i][depth[i]], dfn[pos][depth[i]] + 1, sz[i][depth[i]]);
		tmp.val += query(segrt[i], 1, sz[i][depth[i]], dfn[pos][depth[i]], dfn[pos][depth[i]]).val - w[pos];
		ans = ans + tmp;
		if (!depth[i]) {
			break;
		}
	}
	cout << (pos = id[ans.rt][ans.pos - 1]) << ' ';
}
cout << '\n';
#ifdef siriehn_nx
cerr << "The time of this EXE is " << (((double) clock()) / CLOCKS_PER_SEC) << "s\n";
#endif
return 0;
}
posted @ 2021-09-19 15:16  siriehn_nx  阅读(66)  评论(0编辑  收藏  举报