[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;
}