2019 上海网络赛 12/12

秦皇岛死亡惨重,竟然发现无人会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+diszmin{ disyposx<=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+disz2disyx<=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 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值