当前位置: 首页 > news >正文

题解:uoj695 【候选队互测2022】毛估估就行

题意:给出一个无向无权图,\(q\) 次询问两点距离,但是假设真实距离为 \(d\),输出 \([d-1,d+1]\) 都视为正确。\(n\le 8000,q\le 10^6,m\le n^2\)

做法:

正常的最短路肯定是没法做,做出来就得图灵奖了。注意到输出 \(|ans-d|\le 1\) 都可以,我们考虑去找一些关键点出来对整个图跑 bfs,假设 \((x,y)\) 的最短路径经过关键点 \(u\) 或者 \(u\) 的邻域,那么就会有 \(dis(x,u)+dis(y,u)-2\le dis(x,y)\le dis(x,u)+dis(y,u)\)。直接输出 \(dis(x,u)+dis(y,u)-1\) 就可以保证是对的。询问时不太方便去找 \(u\),但是我们发现对所有的关键点取 \(\min\) 肯定是没问题的,不相邻的肯定差的更多,这样输出就可以了。

但是这样显然不够快,还是 \(O(n)\) 个关键点和 \(O(n^2)\) 的 bfs 合起来是 \(n^3\) 的。我们考虑,当我们拉出来一个关键点后,我们就直接把他和他的邻域全删了,不用在后面的 bfs 中跑。这样并没有时间复杂度保证,但是如果我们换成优先选度数更大的点就有保证了,可以证明是 \(O(n^2)\) 的,接下来我们说明一下这个事情。

假设我们做到第 \(i\) 个关键点的时候剩下 \(m_i\) 条边,那么这个关键点目前的度数一定 \(\ge \frac{2m_i}{n}\),也就是我们会同时删除的点的个数。那么我们会有:

\[\sum\frac{2m_i}n\le \sum deg_{p_i} + 1=n \]

第二个等号的原因是因为所有的点和其邻域的点只会被删一次。

那么我们总共 bfs 的复杂度就是 \(O(\sum m_i) = n^2\)

这样我们可以做到预处理 \(O(n^2)\),询问 \(O(nq)\)

发现这样预处理和询问非常不协调,考虑平衡一下,我们不拉出来 \(n\) 个关键点,而是选前 \(B\) 个。对于剩下没删掉的点就直接暴力跑出两点距离,输出就直接对暴力的和有关键点的取 \(\min\) 即可,询问复杂度 \(O(qB)\)

考虑预处理,首先前面的 bfs 部分肯定还是不大于 \(O(n^2)\) 的复杂度,不用管,主要是后面的复杂度。我们注意到,此时每个点的度数最多为 \(\frac{n}B\),因为如果有多的,那么前面每轮至少删掉 \(\frac{n}B\) 个就删空了,这样总边数就是 \(O(\frac{n^2}{B})\) 的,暴力 bfs 复杂度为 \(O(\frac{n^3}{B})\)

\(B = \sqrt{n^3q}\) 即可,复杂度 \(O(n^{1.5}q^{0.5})\)

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 8005;
int deg[maxn], n, q;
vector<int> e[maxn];
int get_val(char c) {return (isdigit(c) ? c - '0' : c - 'A' + 10);
}
void del(int x) {deg[x] = -1;for (vector<int>::iterator it = e[x].begin(); it != e[x].end(); it++)if(deg[*it] != -1)deg[*it]--;
}
int dis[maxn][maxn];
void bfs(int s) {queue<int> q;dis[s][s] = 0;q.push(s);while(!q.empty()) {int u = q.front(); q.pop();for (vector<int>::iterator it = e[u].begin(); it != e[u].end(); it++) {int v = *it;if(deg[v] != -1 && dis[s][v] > dis[s][u] + 1) {dis[s][v] = dis[s][u] + 1;q.push(v);}}}
}
int p[maxn];
int main() {ios::sync_with_stdio(false);cin >> n >> q;for (int i = 2; i <= n; i++) {string s; cin >> s;for (int j = 1; j < i; j++) {int t = get_val(s[(j - 1) / 4]);if((t >> ((j - 1) % 4)) & 1)e[i].push_back(j), e[j].push_back(i), deg[i]++, deg[j]++;}}memset(dis, 0x3f, sizeof(dis));int B = 100;for (int i = 1; i <= B; i++) {int pos = 0;for (int j = 1; j <= n; j++)if(deg[j] > deg[pos])pos = j;if(pos == 0)break;p[i] = pos;bfs(pos);del(pos);for (vector<int>::iterator it = e[pos].begin(); it != e[pos].end(); it++)if(deg[*it] != -1)del(*it);}for (int i = 1; i <= n; i++) {if(deg[i] == -1)continue;vector<int> res;for (int j = 0; j < e[i].size(); j++)if(deg[e[i][j]] != -1)res.push_back(e[i][j]);swap(res, e[i]);}for (int i = 1; i <= n; i++) {if(deg[i] != -1)bfs(i);}while(q--) {int x, y; cin >> x >> y;int ans = dis[x][y];for (int i = 1; i <= B; i++)if(p[i])ans = min(ans, dis[p[i]][x] + dis[p[i]][y] - 1);cout << ans << '\n';}return 0;
}
http://www.gsyq.cn/news/37745.html

相关文章:

  • 华为Matebook清灰之后扬声器没声音
  • string.replace替换null
  • 类和对象-多态project09
  • CF1730D Prefixes and Suffixes
  • 广告投放名词
  • [LangChain] Runnable接口 - 1
  • 初识目标检测
  • LVGLSharp:LVGL的C#绑定库介绍
  • 论文应该这样读(How to Read a Paper)
  • range()
  • MySQL数据库常用命令
  • Zabbix执行Ping脚本报错,Global script execution被禁用
  • 2025 年 11 月氨糖厂家最新推荐,高性能与可靠性兼具的优质品牌
  • 构建现代Web应用:使用React框架打造单页面应用
  • 面向院区病房的空间智能体新范式:下一代病房框架研究(上)
  • 实用指南:用 Go 并发优化用户中心 API:goroutine 和 errgroup 的实战魔法
  • 夸克网盘免费领取1TB空间的方法
  • 前端三剑客——javascript函数作用域与内置函数
  • 完全背包内外循环是否能对调?
  • 2025 年 11 月快速卷帘门厂家最新推荐,技术实力与市场口碑深度解析!
  • 微信小脚本的校园生活助手系统
  • 震卦、困卦、中孚卦
  • [2025.11.2 鲜花] trick or treat
  • 基于MATLAB绘制CALIPSO Level 2产品中体积退偏比垂直廓线和频率分布直方图
  • Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
  • 2025 年 11 月弹簧片厂家推荐排行榜,304弹簧片,301弹簧片,不锈铁,430不锈钢板材公司推荐
  • 2025 年 11 月办公家具厂家推荐排行榜,办公桌,办公椅,文件柜,会议桌,办公沙发公司推荐,品质与设计双重保障!
  • 【C语言】进程间通信
  • MySQL性能分析(五)之status详解
  • JavaScript笔记(1)