题解 P1131 [ZJOI2007]时态同步
Starlight237 · · 个人记录
智商不够,数据结构来凑
首先有个显而易见的性质,最后所有的叶子结点的时态都等于初始情况下最大的那个时态。
我们将这个最大的时态记作
那么对于每个叶子结点 d,我们需要在
我们在每个结点 i 上记录一个值
观察这样一个性质:若有叶子节点
这是因为在公共部分使用道具一定优于分别对每个叶子使用道具,且任何情况下一条链上使用道具的次数+这条链下方任何叶子结点的dep不能大于maxdep。
因此就可以用树链剖分来维护。对于每个叶子节点把
区间取min?吉司机线段树?不会qwq
我们注意到所有修改操作的端点都在 s (根),那么显然
那么就好办了,暴力往上跳链即可。
注意到
因此最后统计答案的时候差分一下,每条边求和即可。
#include<bits/stdc++.h>
using namespace std;
#define reg register
#define LL long long
#define int long long
extern "C" {
namespace io{
#define BUFS 100000
static char in[BUFS], *p = in, *pp = in;
#define gc() (p == pp && (pp = (p = in) + fread(in, 1, BUFS, stdin), p == pp) ? EOF : *p++)
inline char gtc() {while (isspace(*p)) ++p; return *p++;}
inline LL read() {
reg LL x = 0; reg char ch, f = 0;
while (!isdigit(ch = gc())) f |= ch == '-';
while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
return f ? -x : x;
}
}}
#define rd io :: read
#define gtc io :: gtc
const int N = 500001;
int n, s, tot, head[N], siz[N], son[N], top[N], fa[N], dep[N], dfn[N], tim;
struct Edge{int v, w, nxt;} eg[N << 1];
inline void addedge(int u, int v, int w) {
eg[++tot] = Edge{v, w, head[u]}, head[u] = tot;
}
void dfs1(int x, int Fa, int Dep) {
fa[x] = Fa, dep[x] = Dep, siz[x] = 1;
for (reg int i = head[x], v; i; i = eg[i].nxt)
(v = eg[i].v) != Fa && (
dfs1(v, x, Dep + eg[i].w),
siz[x] += siz[v],
siz[v] > siz[son[x]] && (son[x] = v)
);
}
void dfs2(int x, int Top) {
dfn[x] = ++tim, top[x] = Top;
son[x] && (dfs2(son[x], Top), 0);
for (reg int i = head[x], v; i; i = eg[i].nxt)
dfn[v = eg[i].v] || (dfs2(v, v), 0);
}
int seg[N << 2], tag[N << 2];
inline void pushup(int x) {
seg[x] = min(seg[x << 1], seg[x << 1 | 1]);
}
inline void pushdown(int x) {
~tag[x] && (seg[x << 1] = seg[x << 1 | 1] = tag[x << 1] = tag[x << 1 | 1] = tag[x], tag[x] = -1);
}
void assign(int k, int l, int r, int ll, int rr, int v) {
if (ll > rr) return;
if (ll <= l && r <= rr) {
tag[k] = seg[k] = v; return;
}
int mid = l + r >> 1;
pushdown(k);
ll <= mid && (assign(k << 1, l, mid, ll, rr, v), 0),
mid < rr && ( assign(k << 1 | 1, mid + 1, r, ll, rr, v), 0);
pushup(k);
}
int query(int k, int l, int r, int ll, int rr) {
if (l == r || ll <= l && r <= rr) return seg[k];
int mid = l + r >> 1, sm = 0x3f3f3f3f;
pushdown(k);
ll <= mid && (sm = min(sm, query(k << 1, l, mid, ll, rr))),
mid < rr && ( sm = min(sm, query(k << 1 | 1, mid + 1, r, ll, rr)));
return sm;
}
inline void modify(int x, int v) {
while (x && query(1, 1, n, dfn[top[x]], dfn[x]) >= v)
assign(1, 1, n, dfn[top[x]], dfn[x], v), x = fa[top[x]];
if (!x) return;
int y = x;
while (x != top[x] && query(1, 1, n, dfn[x], dfn[x]) >= v) x = fa[x];
assign(1, 1, n, dfn[x] + 1, dfn[y], v);
}
int maxdep;
LL ans;
void dfs3(int x, int Fa) {
son[x] || (modify(x, maxdep - dep[x]), 0);
for (reg int i = head[x], v; i; i = eg[i].nxt)
(v = eg[i].v) != Fa && (dfs3(v, x), 0);
}
void dfs4(int x, int Fa, int Add) {
for (reg int i = head[x], v, t; i; i = eg[i].nxt)
(v = eg[i].v) != Fa && (
t = query(1, 1, n, dfn[v], dfn[v]),
ans += t - Add,
dfs4(v, x, t), 0
);
}
signed main() {
memset(seg, 0x3f, sizeof seg),
memset(tag, -1, sizeof tag);
n = rd(), s = rd();
for (reg int i = 1, u, v, w; i < n; ++i)
u = rd(), v = rd(), w = rd(), addedge(u, v, w), addedge(v, u, w);
dfs1(s, 0, 0), dfs2(s, s);
for (reg int i = 1; i <= n; ++i) maxdep = max(maxdep, dep[i]);
dfs3(s, 0), dfs4(s, 0, 0);
printf("%lld", ans);
return 0;
}