首页 > 其他分享 >P9678 题解

P9678 题解

时间:2025-01-21 21:53:36浏览次数:1  
标签:std le int 题解 分治 P9678 st vec

题意

给定一棵 \(n\) 个点的树 \(T\),边有边权。现在有 \(q\) 组询问,每组询问给出 \(l, r\),求出:

\[\min_{l \le i < j \le r} \operatorname{dist}(i, j) \]

\(n \le 2 \times 10^5\), \(q \le 10^6\), \(1 \le w \le 10^9\)。

由于与路径长度有关,所以考虑点分治或者 LCA。由于笔者思考 LCA 无果所以这篇题解的做法是点分治。

考虑点分治,对于一个分治过程,我们考虑计算出分治块内点对对询问的贡献。对于分治块内的点 \(x\),记 \(x\) 到分治重心的距离为 \(d_x\)。根据 Shik and Travel 的一个 trick,考虑只记录有用的点对,什么点对是有用的?对于点对 \((x, y)\),如果存在 \((x', y')\) 使得 \(x \le x' < y' \le y\) 且 \(d_x + d_y \ge d_{x'} + d_{y'}\),那么 \((x, y)\) 是有用的。因为点对 \((x', y')\) 能贡献到更多的询问,并且其 \(\operatorname{dist}\) 还更小,所以 \((x, y)\) 可以被 \((x', y')\) 完全代替。当分治块内不存在更好的点对时,\((x, y)\) 就是有用的。

同时,这里不对每个点来自哪个分治重心的儿子区分,因为如果两个点属于同一个子树,在继续往下分治时这两个点的贡献会被重新计算。在当前分治过程中,即使将两点距离计算错误也不会对最终答案产生影响。

有用的点对有多少呢?观察到当 \(y' = y\) 时,有 \(d_x < d_{x'}\),当 \(x' = x\) 时,有 \(d_y < d_{y'}\),所以有:\(\max(d_x, d_y) < \min_{i = x + 1}^{y - 1} d_i\)。于是我们有了一个找出所有有用点对的方法:将所有点按照编号从小到大排成一个序列,对于点 \(x\),找到左边第一个满足 \(d_l \le d_x\) 的 \(l\) 和右边第一个满足 \(d_r \le d_x\) 的 \(r\),\((x, l)\) 和 \((x, r)\) 就是两个有用的点对。根据这个方法,我们同样证明了有用的点对数量是 \(\mathcal{O}(s)\) 的,其中 \(s\) 是分治块大小,总点对数量就是 \(\mathcal{O}(\sum s) = \mathcal{O}(n \log n)\)。

现在问题转化成对于每个询问 \((l, r)\),找到 \(l \le x < y \le r\) 的最近有用点对,按 \(l\) / \(x\) 从大到小排序之后,扫描线+树状数组即可。总时间复杂度 \(\mathcal{O}(n \log^2 n + q\log n)\)。

代码
#include <bits/stdc++.h>

using u32 = unsigned;
using i64 = long long;
using u64 = unsigned long long;

constexpr int N = 2E5 + 5, Q = 1E6 + 5;

int n, q;
std::vector<std::array<int, 2>> adj[N];

int k;
struct Data {
	int x, y;
	i64 d;
	int type;

	constexpr bool operator<(const Data& w) const {
		return x == w.x ? y == w.y ? type < w.type : y < w.y : x > w.x;
	}
} a[N * 60 + Q];

bool vis[N];
int siz[N], maxs[N];
int dsum, root;
i64 d[N];

i64 ans[Q];

void getroot(int x, int par) {
	siz[x] = 1;
	maxs[x] = 0;
	for (auto [y, z] : adj[x]) {
		if (y == par || vis[y]) {
			continue;
		}
		d[y] = d[x] + z;
		getroot(y, x);
		siz[x] += siz[y];
		maxs[x] = std::max(maxs[x], siz[y]);
	}
	maxs[x] = std::max(maxs[x], dsum - siz[x]);
	if (!root || maxs[root] > maxs[x]) {
		root = x;
	}
}
void solve(int x, int nsum) {
	root = 0;
	dsum = nsum;
	getroot(x, x);
	vis[x = root] = 1;
	d[root] = 0;
	getroot(x, x);

	std::vector<std::pair<int, i64>> vec;
	auto dfs = [&](auto &&self, int x, int par) -> void {
		vec.push_back({x, d[x]});
		for (auto [y, z] : adj[x]) {
			if (!vis[y] && y != par) {
				self(self, y, x);
			}
		}
	} ;
	dfs(dfs, x, x);

	int m = vec.size();
	std::sort(vec.begin(), vec.end());

	std::stack<int> st;

	auto push = [&]() {
		for (int i = 0; i < m; ++i) {
			while (!st.empty() && vec[st.top()].second >= vec[i].second) {
				a[++k] = {vec[st.top()].first, vec[i].first, vec[st.top()].second + vec[i].second, 0};
				st.pop();
			}
			st.push(i);
		}
		while (!st.empty()) {
			st.pop();
		}
	} ;

	push();
	std::reverse(vec.begin(), vec.end());
	push();

	for (auto [y, z] : adj[x]) {
		if (!vis[y]) {
			solve(y, siz[y]);
		}
	}
}

struct Fenwick {
	i64 c[N];

	Fenwick() {
		for (int i = 0; i < N; ++i) {
			c[i] = 1E15;
		}
	}

	void insert(int x, i64 val) {
		for (; x <= n; x += x & -x)
			c[x] = std::min(c[x], val);
	}
	i64 query(int x) {
		i64 res = 1E15;
		for (; x; x -= x & -x) {
			res = std::min(res, c[x]);
		}
		return res;
	}
} fen;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	std::cin >> n;
	for (int i = 1; i < n; ++i) {
		int u, v, w;
		std::cin >> u >> v >> w;
		adj[u].push_back({v, w});
		adj[v].push_back({u, w});
	}

	solve(1, n);

	for (int i = 1; i <= k; ++i) {
		if (a[i].x > a[i].y) std::swap(a[i].x, a[i].y);
	}

	std::cin >> q;

	for (int i = 1; i <= q; ++i) {
		int l, r;
		std::cin >> l >> r;
		a[++k] = {l, r, i, 1};
	}

	std::sort(a + 1, a + 1 + k);

	for (int i = 1; i <= k; ++i) {
		if (a[i].type == 1) ans[a[i].d] = fen.query(a[i].y);
		else fen.insert(a[i].y, a[i].d);
	}

	for (int i = 1; i <= q; ++i) {
		std::cout << (ans[i] == 1E15 ? -1 : ans[i]) << "\n";
	}

	return 0;
}

标签:std,le,int,题解,分治,P9678,st,vec
From: https://www.cnblogs.com/CTHOOH/p/18684414

相关文章

  • ZJOI2010 基站选址 题解
    ZJOI2010基站选址题解题目链接dp+线段树优化。暴力dp状态设计:自然想到设\(f(i,j)\)表示只考虑前\(i\)个村庄,在前\(i\)个村庄中建\(j\)个基站,并且在第\(i\)个存在建立基站时,最小的费用。转移:转移时,枚举上一个建基站的村庄\(p\)(这同时告诉我们,\(j=1\)......
  • P1048 [NOIP2005 普及组] 采药 题解
    原题链接题目大意:采药,每种药只有一株,每株有它的价值和采它所需的时间,现时间有限,请你输出在有限时间内能获得的价值最大是多少。分析:1.这是一个典型的01背包问题(DP)01背包问题的典型特征:有一个限定容量的背包(对应本题中的时间),有物品(每种只有一个)(对应本题中的药株),物品有......
  • 洛谷P1002 [NOIP2002 普及组] 过河卒 题解
    原题链接题目大意:棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:向下或向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。棋盘用坐标表示,AA点(0,0)、BB点(n,m),同样马的位置坐标是需要给出的。现在要求你计算出......
  • 2025牛客寒假算法基础集训营1 ptlks的题解
    A.茕茕孑立之影题意:给定序列,找出一个数x,满足x和数组中任意一个元素都互不为倍数关系思路x范围为1e18以内,序列元素范围为1e9以内,选大于1e9的质数即可,特判序列中有1的情况。代码点击查看代码voidsolve(){ intn; cin>>n; intf=1; for(inti=1;i<=n;i++){ cin>>a[......
  • 题解:洛谷 P4879 ycz的妹子
    题目https://www.luogu.com.cn/problem/P4879感觉还比较简单的线段树。首先我们先建立一棵线段树(范围:)。voidbuild(intk,intl,intr){ tr[k]={l,r}; if(l==r){ Tree[k]=a[l],c[k]=(l<=n); return; } intmid=(l+r)>>1ll; build(k<<1ll,l,mid); build((k<<1ll)|1l......
  • 题解:洛谷 P1351 [NOIP2014 提高组] 联合权值
    题目https://www.luogu.com.cn/problem/P1351我们可以发现,若点对  的距离为 ,则它们一定会经过一个中转点,因此我们考虑枚举中转点 ,然后枚举与  有直接边连接的两个点,按照题意统计答案即可。#include<bits/stdc++.h>usingnamespacestd;#pragmaG++optimisze(3,"Ofas......
  • 【题解】Luogu P4340 [SHOI2016] 随机序列
    简单手摸后发现,答案就是这么一个式子:\[(3^{n-1}-3^{n-2})a_1+(3^{n-2}-3^{n-3})a_1a_2+\dots+(3^1-3^0)a_1a_2\dotsa_{n-1}+a_1a_2\dotsa_n\]啊当然证明也是好证的,对于\(a_1\)这一项,它后面放+或-都会对系数加一,而放*不会影响系数,因此系数就是总数的三分之二。其它前缀......
  • 题解:P3823 [NOI2017] 蚯蚓排队
    题目链接https://www.luogu.com.cn/problem/P3823分析先解决队伍的合并与分离问题。使用链表结构,分别维护每只蚯蚓的前驱和后继即可。然后考虑如何统计答案。可以对每只蚯蚓的“向后\(k\)数字串”使用字符串哈希的方式获得哈希值,再用一个哈希表存储每个哈希值出现的次数。对......
  • 2024 (ICPC) Jiangxi Provincial Contest I 题 Neuvillette Circling题解
    简单思路一个圆套中了几个点,如果不断缩小这个圆,那么最终的结果有两种有两个点卡住了这个圆,且这两点一定是直径有三个或者三个以上的点卡住了这个圆,圆心在这三个点围成的三角形的外接圆圆心。因此我们枚举两点作为直径,或者枚举三个点作为圆的内接三角形,求这个三角形的外接圆......
  • 2024 (ICPC) Jiangxi Provincial Contest L 题 Campus 题解
    简单思路首先对于所有的出口求一遍最短路,由于出口只会打开并关闭一次,所以大门的开启状态是相当有限的(最多大概30种),我们对于每一种状态直接暴力求答案最后输出即可。复杂度大概\(O(knlogn)\)参考代码#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;type......