秦皇岛死亡惨重,竟然发现无人会tarjan,现场现学3h,3h时我们队才1题,最后差5分钟出E,差点上演2h从铁到金。。。。回来补题
花了一天补完啦呼啦啦
A
这题可以直接维护直径,只改边权的动态维护直径是可以做到 O ( n l o g n ) O(nlogn) O(nlogn)的。你考虑维护欧拉序,那么直径端点假如是 x , z x,z x,z,那么可以写成
d i s x + d i s z − m i n { d i s y ∣ p o s x < = y < = p o s z } dis_x + dis_z - min\{dis_y | pos_x <= y <= pos_z\} disx+disz−min{
disy∣posx<=y<=posz}
其中 p o s x , p o s z pos_x, pos_z posx,posz为其欧拉序中第一次出现的位置, d i s x dis_x disx表示 x x x到根的距离。
那么实际上就是要求一段中的
m a x { d i s x + d i s z − 2 ∗ d i s y ∣ x < = y < = z } max\{dis_x + dis_z - 2 * dis_y | x <= y <= z\} max{
disx+disz−2∗disy∣x<=y<=z}
我们可以考虑维护 x , z x, z x,z以及他们把线段分成了3部分,每一部分的距离最小值。(这里是cf1192B)
那么你就组合一下就可以得到直径。
对于这题实际上就是动态维护直径,然后答案一定是 x x x到直径的某个端点。
用上诉做法就可以做到 O ( n l o g n ) O(nlogn) O(nlogn)了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
using ll = long long;
ll min(ll a, ll b, ll c) {
return min(a, min(b, c));
}
int const N = 100005;
int const LOGN = 19;
struct edge {
int y, next;
ll w;
} e[N << 1];
int last[N], ne;
struct bian {
int x, y;
ll w;
} b[N];
void addedge(int x, int y, ll w) {
e[++ne] = {
y, last[x], w };
last[x] = ne;
}
int beg[N], en[N], ver[N << 1], tot;
ll dis[N];
int n, m;
int fa[N][LOGN];
int deep[N];
int get_lca(int x, int y) {
if (deep[x] < deep[y])
swap(x, y);
for (int i = LOGN - 1; i >= 0; --i)
if (deep[fa[x][i]] >= deep[y])
x = fa[x][i];
if (x == y)
return x;
for (int i = LOGN - 1; i >= 0; --i)
if (fa[x][i] != fa[y][i]) {
x = fa[x][i];
y = fa[y][i];
}
return fa[x][0];
}
void dfs(int x, ll dep, int pre) {
fa[x][0] = pre;
for (int i = 1; i < LOGN; ++i)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
deep[x] = deep[pre] + 1;
ver[++tot] = x;
beg[x] = en[x] = tot;
dis[x] = dep;
for (int i = last[x]; i; i = e[i].next) {
if (e[i].y == pre)
continue;
dfs(e[i].y, dep + e[i].w, x);
ver[++tot] = x;
en[x] = tot;
}
}
struct segNode {
int x, z;
ll dx, dz;
ll mi[3];
ll lz;
} t[N << 3];
inline ll calc_dis(segNode const& x) {
return x.dx + x.dz - 2 * x.mi[1];
}
void merge(segNode& ret, segNode const& ls, segNode const& rs) {
static segNode ts[6];
ts[0] = ls;
ts[0].mi[2] = min(ts[0].mi[2], min(rs.mi[0], rs.mi[1], rs.mi[2]));
ts[0].lz = ret.lz;
ts[1] = rs;
ts[1].mi[0] = min(ts[1].mi[0], min(ls.mi[0], ls.mi[1], ls.mi[2]));
ts[1].lz = ret.lz;
ts[2] = {
ls.x, rs.x, ls.dx, rs.dx, ls.mi[0],
min(ls.mi[1], ls.mi[2], rs.mi[0]),
min(rs.mi[1], rs.mi[2]), ret.lz };
ts[3] = {
ls.x, rs.z, ls.dx, rs.dz, ls.mi[0],
min(min(ls.mi[1], ls.mi[2]), min(rs.mi[0], rs.mi[1])),
rs.mi[2], ret.lz };
ts[4] = {
ls.z, rs.x, ls.dz, rs.dx, min(ls.mi[0], ls.mi[1]),
min(ls.mi[2], rs.mi[0]),
min(rs.mi[1], rs.mi[2]), ret.lz };
ts[5] = {
ls.z, rs.z, ls.dz, rs.dz, min(ls.mi[0], ls.mi[1]),
min(ls.mi[2], rs.mi[0], rs.mi[1]),
rs.mi[2], ret.lz };
ll l = -1, tl, num = -1;
for (int i = 0; i < 6; ++i)
if ((tl = calc_dis(ts[i])) > l) {
l = tl;
num = i;
}
ret = ts[num];
// cerr << "! : " << num << ' ' << ret.dx << ' ' << ret.dz << ' ' << ls.mi[1] << ' ' << ls.mi[2] << ' ' << rs.mi[0] << '\n';
}
void apply(int k, ll val) {
t[k].dx += val;
t[k].dz += val;
t[k].mi[0] += val;
t[k].mi[1] += val;
t[k].mi[2] += val;
t[k].lz += val;
}
void pushdown(int k) {
apply(k << 1, t[k].lz);
apply(k << 1 | 1, t[k].lz);
t[k].lz = 0;
}
void build(int k, int l, int r) {
if (l == r) {
t[k].x = t[k].z = ver[l];
t[k].dx = t[k].dz = dis[ver[l]];
t[k].mi[0] = t[k].mi[1] = t[k].mi[2] = dis[ver[l]];
return;
}
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
t[k].lz = 0;
merge(t[k], t[k << 1], t[k << 1 | 1]);
}
void modify(int k, int l, int r, int ql, int qr, ll val) {
if (ql <= l && r <= qr) {
apply(k, val);
return;
}
if (t[k].lz)
pushdown(k);
int mid = (l + r) >> 1;
if (ql <= mid)
modify(k << 1, l, mid, ql, qr, val);
if (qr > mid)
modify(k << 1 | 1, mid + 1, r, ql, qr, val);
merge(t[k], t[k << 1], t[k << 1 | 1]);
}
ll query(int k, int l, int r, int pos) {
if (l == r)
return t[k].dx;
if (t[k].lz)
pushdown(k);
int mid = (l + r) >> 1;
ll ret;
if