CF293E Close Vertices 题解

看着就像点分治,但会发现和模板有些不同,多了一维。

我们还是照着模板的做法,分治求出重心,然后深搜找出每个点到重心的距离。不过我们这里要求两个,分别是长度 dud_u 和边权和 pup_u

考虑枚举一个点 uu。如果这个点和另外一个点 vv 是满足条件的,那么必有 du+dvld_u + d_v \leq lpu+pvwp_u + p_v \leq w,最重要的,uuvv 在以重心为根的两个子树中。

在两个子树中其实很好处理,我们先抛开这个条件,算出所有的 u,vu,v,再减去每个子树中的数量即可。

那么如何求这个东西呢?枚举 uu,我们知 dvldud_v \leq l - d_upvwpup_v \leq w - p_u。容易发现这是个二位偏序,离线树状数组等一些数据结构均可维护。复杂度 O(nlog2n)O(n \log^2 n)

不过具体还是有些细节的,例如树状数组可能统计到一对 u=vu=v,又或者统计到两对 u,vu,vv,uv,u。注意细节即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
#define ll long long

const int N = 1e5 + 5;

vector<pair<int, ll> > G[N];

int n, l;
ll w;

bool del[N];
int sz[N], dis1[N], wc, tot;
ll dis2[N];
vector<pair<int, ll> > v;

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

void dfs_wc(int u, int fa)
{
	if (del[u]) return;
	int maxn = 0, sum = 1;
	for (auto& j : G[u])
	{
		if (j.first == fa) continue;
		dfs_wc(j.first, u);
		maxn = max(maxn, sz[j.first]);
		sum += sz[j.first];
	}
	maxn = max(maxn, tot - sum);
	if (maxn <= tot / 2)
	{
		wc = u;
	}
}

void dfs_dist(int u, int fa, int d1, ll d2, ll len)
{
	dis1[u] = dis2[u] = 0;
	if (del[u]) return;
	dis1[u] = d1 + 1;
	dis2[u] = d2 + len;
	v.emplace_back(make_pair(dis1[u], dis2[u]));
	for (auto& j : G[u])
	{
		if (j.first != fa)
		{
			dfs_dist(j.first, u, dis1[u], dis2[u], j.second);
		}
	}
}

int cc = 0;

class Bit
{
public:
	int tr[N];
	int lowbit(int x)
	{
		return x & -x;
	}
	void update(int x, int v)
	{
		while (x < N)
		{
			tr[x] += v;
			x += lowbit(x);
		}
	}
	int query(int x)
	{
		int res = 0;
		while (x)
		{
			res += tr[x];
			x -= lowbit(x);
		}
		return res;
	}
}bt;

inline bool cmp(const pair<int, ll>& x, const pair<int, ll>& y)
{
	return x.second < y.second;
}

vector<pair<int, ll> > QRY;

map<ll, vector<int> > mp;

inline ll calc(int u) 
{
	if (del[u])
	{
		return 0;
	}
	ll res = 0;
	dfs_sz(u, 0);
	tot = sz[u];
	wc = 0;
	dfs_wc(u, 0);
	u = wc;
	if (del[u]) return 0;
	del[u] = 1;
	if (!u) return 0LL;
	vector<pair<int, ll> > total;
	ll css = 0;
	for (auto& j : G[u])
	{
		if (del[j.first]) continue;
		mp.clear();
		QRY.clear();
		v.clear();
		dfs_dist(j.first, u, 0, j.second, 0);
		for (int i = 0; i < v.size(); i++)
		{
			total.emplace_back(v[i]);
			auto k = v[i];
			if (k.first <= l && k.second <= w)
			{
				res++;
			}
			if (l - k.first >= 0 && w - k.second >= 0)
			{
				QRY.emplace_back(make_pair(l - k.first, w - k.second));
				if (l - k.first >= k.first && w - k.second >= k.second)
				{
					css++;
				}
			}
		}
		sort(v.begin(), v.end(), cmp);
		for (auto i : QRY)
		{
			auto it = upper_bound(v.begin(), v.end(), i, cmp);
			if (it == v.begin())
			{
				continue;
			}
			else mp[(*(--it)).second].emplace_back(i.first);
		}
		for (int p = 0; p < v.size(); p++)
		{
			bt.update(v[p].first, 1);
			if (p == v.size() - 1 || v[p + 1].second != v[p].second)
			{
				for (auto pp : mp[v[p].second])
				{
					css -= bt.query(pp);
				}
			}	
			
		}
		for (auto& p : v)
		{
			bt.update(p.first, -1);
		}
	}
	QRY.clear();
	for (int i = 0; i < total.size(); i++)
	{
		auto k = total[i];
		if (l - k.first >= 0 && w - k.second >= 0)
		{
			QRY.emplace_back(make_pair(l - k.first, w - k.second));
			if (l - k.first >= k.first && w - k.second >= k.second) css--;
		}
	}
	mp.clear();
	sort(total.begin(), total.end(), cmp);
	for (auto i : QRY)
	{
		auto it = upper_bound(total.begin(), total.end(), i, cmp);
		if (it == total.begin())
		{
			continue;
		}
		else mp[(*(--it)).second].emplace_back(i.first);
	}
	for (int p = 0; p < total.size(); p++)
	{
		bt.update(total[p].first, 1);
		if (p == total.size() - 1 || total[p + 1].second != total[p].second)
		{
			for (auto pp : mp[total[p].second])
			{
				css += bt.query(pp);
			}
		}
		
	}
	for (auto& p : total)
	{
		bt.update(p.first, -1);
	}
	for (auto& j : G[u])
	{
		res += calc(j.first);
	}
	//cout << "!: " << u << " " << css << "\n";
	res += css / 2;
	return res;
}

signed main()
{
	//freopen("D:\\1233.txt", "r", stdin);
	//freopen("D:\\1233.ans", "w", stdout);
	ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> l >> w;
	for (int i = 1; i < n; i++)
	{
		int v;
		ll w;
		cin >> v >> w;
		G[i + 1].emplace_back(make_pair(v, w));
		G[v].emplace_back(make_pair(i + 1, w));
	}
	cout << calc(1) << "\n";
	return 0;
}
posted @   HappyBobb  阅读(11)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示