「IOI2017」西默夫 的一个另类做法
我们发现如果我们有一个环套树的话,那么我们可以把这个环套树去掉每一条环上的边\(e\),问一遍有多少御道在这棵树上。假设删去\(e\)后答案为\(A_e\)。
如果答案全部一样,那么说明环上的边都不在御道里面(不可能都在)。否则设答案有\(k\),\(k + 1\)两种。那么如果\(A_e = k\),那么\(e\)在,否则\(e\)就不在了。
我们先随便建一棵生成树,然后先试图确定每条树边是否在御道里面。我们依次考虑每一条非树边,如果加入这条非树边\(e\)后,边双连通分量个数变小了,那么我们考虑它让哪些桥消失。这些桥均在一个环上。那么我们把这个环中所有的桥边、\(e\)和恰好一条非桥边(如果存在的话)给询问一遍,就可以类似地得到\(e\)和所有桥边的状态了!最后所有桥边一定要被选,否则连通性会出问题。
注意到每一步的复杂度可以被边双连通分量的减少量bound住,所以这一步询问次数为\(O(n)\)。
之后我们把还未确定状态的那些边定向,方向为编号较大的点到编号较小的点。然后对每个点的出边,我们用分治的方法来求出每条边是否是御道。
这里我们考虑给定一个出边的子集,找到一棵生成树使得它恰好包含这些出边的子集,而不包含其它出边,且它包含的其它的边状态已知。那么我们询问这棵树,就可以得到有多少出边是御道了。分治大概就是说每次询问左边一半的个数,然后如果有的话就递归左边,类似地判断是否要递归右边。
由于御道个数为\(n - 1\),而对每个点分治的复杂度为这个点的出边的御道个数*\(\log n\),所以总询问次数为\(O(n \log n)\),可以通过此题!
代码如下:
#include "simurgh.h"
#include <bits/stdc++.h>
using namespace std;
const int N = 505, M = N * N;
int V, E, rt[N], col[N], s[M], t[M], ans[M];
vector<int> tree[N], vec;
bool intree[M];
int findroot (int u) {
return rt[u] == u ? u : rt[u] = findroot(rt[u]);
}
int find_tree () {
for (int i = 0; i < E; i++) {
int x = findroot(s[i]), y = findroot(t[i]);
if (x != y) {
intree[i] = true, rt[x] = y;
vec.push_back(i);
tree[s[i]].push_back(i);
tree[t[i]].push_back(i);
}
}
return count_common_roads(vec);
}
int par[N], path[N];
void dfs (int u, int fa) {
for (int i = 0; i < tree[u].size(); i++) {
int id = tree[u][i], v = s[id] == u ? t[id] : s[id];
if (v != fa) {
par[v] = u, path[v] = id;
dfs(v, u);
}
}
}
vector<int> get_route (int u, int v) {
vector<int> route;
dfs(u, -1);
for (int i = v; i != u; i = par[i]) {
if (ans[path[i]] < 0) route.push_back(path[i]);
}
return route;
}
int extra (int u, int v) {
for (int i = v; i != u; i = par[i]) {
if (ans[path[i]] >= 0) return path[i];
}
return -1;
}
void replace (int e1, int e2) {
for (int i = 0; i < vec.size(); i++) {
if (vec[i] == e1) vec[i] = e2;
}
}
void shrink (int u, int v) {
for (int i = v; i != u; i = par[i]) {
if (ans[path[i]] < 0) {
int c = col[i];
for (int j = 0; j < V; j++) {
if (col[j] == c) col[j] = col[u];
}
}
}
}
void query_tree () {
int total = find_tree();
for (int i = 0; i < E; i++) {
if (!intree[i] && col[s[i]] != col[t[i]]) {
vector<int> route = get_route(s[i], t[i]), res;
shrink(s[i], t[i]);
bool flag[3] = {false};
for (int j = 0; j < route.size(); j++) {
replace(route[j], i);
res.push_back(total - count_common_roads(vec));
flag[res[j] + 1] = true, replace(i, route[j]);
}
if (flag[0] || flag[2]) ans[i] = flag[0] ? 1 : 0;
else {
int id = extra(s[i], t[i]);
if (id) {
replace(id, i);
ans[i] = count_common_roads(vec) - total + ans[id];
replace(i, id);
}
else ans[i] = 0;
}
for (int j = 0; j < route.size(); j++) ans[route[j]] = ans[i] + res[j];
}
}
for (int i = 0; i < E; i++) {
if (intree[i] && ans[i] < 0) ans[i] = 1;
}
}
vector<int> g[N];
int query (int u, int l, int r) {
int num = 0;
vec.clear();
for (int i = 0; i < V; i++) rt[i] = i;
for (int i = l; i <= r; i++) {
int id = g[u][i], v = s[id] == u ? t[id] : s[id];
rt[findroot(u)] = rt[findroot(v)];
vec.push_back(id);
}
for (int i = 0; i < E; i++) {
if (intree[i]) {
int x = findroot(s[i]), y = findroot(t[i]);
if (x != y) {
vec.push_back(i);
rt[x] = y, num += ans[i];
}
}
}
return count_common_roads(vec) - num;
}
void solve (int u, int l, int r, int num) {
int mid = l + r >> 1;
if (l == r) ans[g[u][mid]] = (bool)num;
else {
int num_ = num ? query(u, l, mid) : 0;
solve(u, l, mid, num_), solve(u, mid + 1, r, num - num_);
}
}
vector<int> find_roads (int n, vector<int> u, vector<int> v) {
V = n, E = u.size();
for (int i = 0; i < V; i++) col[i] = rt[i] = i;
for (int i = 0; i < E; i++) {
ans[i] = -1, intree[i] = false;
s[i] = u[i], t[i] = v[i];
}
query_tree();
for (int i = 0; i < E; i++) {
if (ans[i] < 0) g[max(s[i], t[i])].push_back(i);
}
for (int i = 0; i < V; i++) {
if (!g[i].empty()) {
int num = query(i, 0, g[i].size() - 1);
solve(i, 0, g[i].size() - 1, num);
}
}
vector<int> tree;
for (int i = 0; i < E; i++) {
if (ans[i]) tree.push_back(i);
}
return tree;
}
「IOI2017」西默夫 的一个另类做法的更多相关文章
- 「IOI2017」接线 的另类做法
看到这题,我的第一反应是:这就是一个费用流模型?用模拟费用流的方法? 这应该是可以的,但是我忘记了怎么模拟费用流了IOI不可能考模拟费用流.于是我就想了另外一个方法. 首先我们考虑模拟费用流的模型如下 ...
- Linux 小知识翻译 - 「日志」(log)
这次聊聊「日志」. 「日志」主要指系统或者软件留下的「记录」.出自表示「航海日志」的「logbook」. 经常听说「出现问题的时候,或者程序没有安装自己预期的来运行的时候,请看看日志!」. 确实,记录 ...
- 「SCOI2016」妖怪 解题报告
「SCOI2016」妖怪 玄妙...盲猜一个结论,然后过了,事后一证,然后假了,数据真水 首先要最小化 \[ \max_{i=1}^n (1+k)x_i+(1+\frac{1}{k})y_i \] \ ...
- P4711 「化学」相对分子质量
P4711 「化学」相对分子质量 给你一个字符串让你输出相对分子质量(弱智字符串模拟) 我比赛tm调了两个半小时啊QAQ 希望以后能增加代码力吧,纪念挂代码 Code #include<iost ...
- 「NOI2018」冒泡排序
「NOI2018」冒泡排序 考虑冒泡排序中一个位置上的数向左移动的步数 \(Lstep\) 为左边比它大的数的个数,向右移动的步数 \(Rstep\) 为右边比它大的数的个数,如果 \(Lstep,R ...
- 「SDOI2005」区间
「SDOI2005」区间 传送门 记录每一个位置作为左端点和右端点的出现次数,然后直接考虑差分即可. 参考代码: #include <cstdio> #define rg register ...
- 「POJ3613」Cow Relays
「POJ3613」Cow Relays 传送门 就一个思想:\(N\) 遍 \(\text{Floyd}\) 求出经过 \(N\) 个点的最短路 看一眼数据范围,想到离散化+矩阵快速幂 代码: #in ...
- Python后端日常操作之在Django中「强行」使用MVVM设计模式
扫盲 首先带大家了解一下什么是MVVM模式: 什么是MVVM?MVVM是Model-View-ViewModel的缩写. MVVM是MVC的增强版,实质上和MVC没有本质区别,只是代码的位置变动而已 ...
- 10月1日之后,你新建的GitHub库默认分支不叫「master」了
从 2020 年 10 月 1 日开始,GitHub 上的所有新库都将用中性词「main」命名,取代原来的「master」,因为后者是一个容易让人联想到奴隶制的术语. 这个决定并不是最近才做出的.今年 ...
随机推荐
- Docker安装Oracle11g
为什么使用docker安装oracle,因为自己搭建配置的话可能时间太久太繁琐等等原因,也因为docker实在太方便了 本文主要是使用docker-compose安装Oracle 11g,因为使用do ...
- 腾讯云容器服务 TKE 推出新一代零损耗容器网络
随着容器技术的发展成熟,越来越多的组件迁移到容器,在技术迁移过程中,数据库,游戏,AI 这些组件对容器网络性能(时延,吞吐,稳定性)提出了更高的要求.为了得到更优的时延和吞吐表现,各大云厂商都在致力于 ...
- 使用iptables做端口转发
通过iptables可以做转发 #!/bin/sh IPT="/sbin/iptables" /bin/echo "1" > /proc/sys/net/ ...
- 网络发布工具 Apache/Nginx
四大主流发布服务器 注:发布服务器的背后都是socket套接字 1.Apache阿帕奇 - 多进程 2.IIS -多线程 3.Nginx (engine x)(新) -支持异步IO,是现在最快的发布服 ...
- Qt For Android 环境搭建
由于时间有限,未抽出时间进行android环境搭建整理的流程,这里先贴出几个参考的地址 https://blog.csdn.net/foruok/article/details/23528293 此链 ...
- mysql 5.7添加server_audit 安全审计功能
mysql 5.7添加server_audit 安全审计功能 一.根据链接下载插件 参考链接下载 http://blog.itpub.net/31441024/viewspace-2213103 l ...
- [原题复现][2020i春秋抗疫赛] WEB blanklist(SQL堆叠注入、handler绕过)
简介 今天参加i春秋新春抗疫赛 一道web没整出来 啊啊啊 好垃圾啊啊啊啊啊啊啊 晚上看群里赵师傅的buuoj平台太屌了分分钟上线 然后赵师傅还分享了思路用handler语句绕过select过滤.. ...
- 数据丢失如何恢复?EasyRecovery帮你快速实现
在日常使用电脑时,我们经常会遇到误删文件的情况,若文件还未被彻底删除,我们还可以通过电脑中的回收站将其恢复,但若是回收站都被清空的话,想要恢复文件就变得比较困难了,而EasyRecovery可以很好的 ...
- window安装elasticsearch和kibana
本次测试安装5.1.1版本 es下载地址:https://www.elastic.co/downloads/past-releases/elasticsearch-5-1-1 选择zip kibana ...
- PHP 递归删除目录中文件
/** * 递归删除目录中文件 * @param $pathname * @return bool */public static function delDir($pathname)//要删除的目录 ...