P4115 Qtree4

提供点分树做法。

先考虑静态问题,发现可以点分治做。具体的,对于每个分治重心,求出每个儿子子树内白点到当前重心的距离最大值。将最大和次大加起来即为两条路径拼接。

考虑动态怎么做?首先建出点分树,每个点维护两个 multiset,记为 sus_utut_u,分别维护 uu 子树内每个白点到 faufa_u 的距离,以及 uu 的每一个儿子的 sus_u 的最大值。注意需要处理这个点的贡献,即为 00

那么每一个 tut_u 的最大和次大值之和即为答案。

考虑修改的时候,只维护这个点到根的路径的 sstt。由于点分树树高 O(logn)O(\log n),所以就可以在 O(qlog2n)O(q \log^2 n) 的复杂度内做完。

然而常数比较大,可以考虑使用懒惰删除堆替代 multiset

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#include <queue>
#include <set>
using namespace std;

const int N = 1e5 + 5, INF = 2e9;

int n, m;
vector<pair<int, int> > G[N];
vector<int> NG[N];
int fa[N], sz[N], dep[N], sum[N];
bool del[N];
bool col[N];
int tot, wc;

class My_Heap
{
public:
	priority_queue<int> p, q;
	void insert(int x)
	{
		p.push(x);
	}
	void erase(int x)
	{
		q.push(x);
	}
	void update()
	{
		if (p.size() < q.size()) exit(-1);
		while (q.size() && p.top() == q.top())
		{
			p.pop(), q.pop();
		}
	}
	int sz()
	{
		if (p.size() < q.size()) exit(-1);
		return p.size() - q.size();
	}
	int top()
	{
		update();
		return p.top();
	}
	int sec()
	{
		int x = top();
		update();
		if (p.empty()) exit(-1);
		p.pop();
		int y = top();
		insert(x);
		return y;
	}
	int res()
	{
		return top() + sec();
	}
}st[N], st2[N], ans;

class TreeCut
{
private:
	int dep[N], fa[N], son[N], top[N], id[N], sz[N], cnt = 0;
	void dfs1(int u, int father, int depth)
	{
		dep[u] = depth;
		fa[u] = father;
		sz[u] = 1;
		for (int i = 0; i < G[u].size(); i++)
		{
			int nx = G[u][i].first;
			if (nx == father) continue;
			dfs1(nx, u, depth + 1);
			sz[u] += sz[nx];
			if (sz[son[u]] < sz[nx]) son[u] = nx;
		}
	}
	void dfs2(int u, int tf)
	{
		top[u] = tf;
		id[u] = ++cnt;
		if (!son[u]) return;
		dfs2(son[u], tf);
		for (int i = 0; i < G[u].size(); i++)
		{
			int nx = G[u][i].first;
			if (nx == fa[u] || nx == son[u]) continue;
			dfs2(nx, nx);
		}
	}
public:
	void build()
	{
		dfs1(1, 1, 1);
		dfs2(1, 1);
	}
	int LCA(int x, int y)
	{
		while (top[x] ^ top[y])
		{
			if (dep[top[x]] < dep[top[y]])
			{
				x ^= y;
				y ^= x;
				x ^= y;
			}
			x = fa[top[x]];
		}
		if (dep[x] < dep[y]) return x;
		return y;
	}
}tc;

void calc_sz(int u, int f)
{
	sz[u] = 0;
	if (del[u]) return;
	sz[u] = 1;
	for (auto& j : G[u])
	{
		if (j.first != f)
		{
			calc_sz(j.first, u);
			sz[u] += sz[j.first];
		}
	}
}

void find_wc(int u, int f)
{
	if (del[u]) return;
	int maxn = tot - sz[u];
	for (auto& j : G[u])
	{
		if (j.first != f)
		{
			find_wc(j.first, u);
			maxn = max(maxn, sz[j.first]);
		}
	}
	if (maxn <= tot / 2) wc = u;
}

int in[N];
vector<int> subtree[N];

void solve(int u, int f)
{
	if (del[u]) return;
	calc_sz(u, 0);
	wc = tot = 0;
	tot = sz[u];
	find_wc(u, 0);
	u = wc;
	del[u] = 1;
	if (f)
	{
		NG[f].emplace_back(u);
		in[u]++;
		fa[u] = f;
		//cout << "!!!: " << f << " " << u << "\n";
	}
	for (auto& j : G[u]) solve(j.first, u);
}

void predfs(int u, int f, int w)
{
	if (!f) dep[u] = 0;
	else dep[u] = dep[f] + 1;
	sum[u] = sum[f] + w;
	for (auto& j : G[u])
	{
		if (j.first != f)
		{
			predfs(j.first, u, j.second);
		}
	}
}

inline int get_dist(const int& x, const int& y)
{
	return sum[x] + sum[y] - 2 * sum[tc.LCA(x, y)];
}

void dfs(int u)
{
	if (col[u] == 0)
	{
		if (fa[u]) st[u].insert(get_dist(u, fa[u]));
		subtree[u].emplace_back(u), st2[u].insert(0);
	}
	for (auto& j : NG[u])
	{
		dfs(j);
		int maxn = -INF;
		for (auto& k : subtree[j])
		{
			subtree[u].emplace_back(k);
			int g = get_dist(u, k);
			maxn = max(maxn, g);
			if (fa[u]) st[u].insert(get_dist(k, fa[u]));
		}
		if (maxn == -INF) continue;
		st2[u].insert(maxn);
	}
}

int rtt = 0;

signed main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n;
	for (int i = 1; i < n; i++)
	{
		int u, v, w;
		cin >> u >> v >> w;
		G[u].emplace_back(make_pair(v, w));
		G[v].emplace_back(make_pair(u, w));
	}
	tc.build();
	solve(1, 0);
	predfs(1, 0, 0);
	//if (!dbg.check()) return -1;
	cin >> m;
	int cnt = n;
	for (int i = 1; i <= n; i++) if (!fa[i]) rtt = i;
	dfs(rtt);
	for (int i = 1; i <= n; i++)
	{
		if (st2[i].sz() >= 2) ans.insert(st2[i].res());
	}
	while (m--)
	{
		char opt;
		cin >> opt;
		if (opt == 'C')
		{
			int x;
			cin >> x;
			if (col[x] == 0)
			{
				if (st2[x].sz() >= 2) ans.erase(st2[x].res());
				st2[x].erase(0);
				if (st2[x].sz() >= 2) ans.insert(st2[x].res());
				for (int i = x; fa[i]; i = fa[i])
				{
					if (st2[fa[i]].sz() >= 2) ans.erase(st2[fa[i]].res());
					int pre = st[i].top();
					st2[fa[i]].erase(pre);
					st[i].erase(get_dist(x, fa[i]));
					if (st[i].sz()) st2[fa[i]].insert(st[i].top());
					if (st2[fa[i]].sz() >= 2) ans.insert(st2[fa[i]].res());
				}
				cnt--;
			}
			else
			{
				if (st2[x].sz() >= 2) ans.erase(st2[x].res());
				st2[x].insert(0);
				if (st2[x].sz() >= 2) ans.insert(st2[x].res());
				for (int i = x; fa[i]; i = fa[i])
				{
					if (st2[fa[i]].sz() >= 2) ans.erase(st2[fa[i]].res());
					if (st[i].sz())
					{
						int pre = st[i].top();
						st2[fa[i]].erase(pre);
					}
					st[i].insert(get_dist(x, fa[i]));
					st2[fa[i]].insert(st[i].top());
					if (st2[fa[i]].sz() >= 2) ans.insert(st2[fa[i]].res());
				}
				cnt++;
			}
			col[x] ^= 1;
		}
		else
		{
			if (cnt == 0) cout << "They have disappeared.\n";
			else if (ans.sz() == 0) cout << "0" << "\n";
			else
			{
				cout << max({ ans.top(), 0 }) << "\n";
			}
		}
	}
	return 0;
}
posted @   HappyBobb  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示