我们发现如果我们有一个环套树的话,那么我们可以把这个环套树去掉每一条环上的边\(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」西默夫 的一个另类做法的更多相关文章

  1. 「IOI2017」接线 的另类做法

    看到这题,我的第一反应是:这就是一个费用流模型?用模拟费用流的方法? 这应该是可以的,但是我忘记了怎么模拟费用流了IOI不可能考模拟费用流.于是我就想了另外一个方法. 首先我们考虑模拟费用流的模型如下 ...

  2. Linux 小知识翻译 - 「日志」(log)

    这次聊聊「日志」. 「日志」主要指系统或者软件留下的「记录」.出自表示「航海日志」的「logbook」. 经常听说「出现问题的时候,或者程序没有安装自己预期的来运行的时候,请看看日志!」. 确实,记录 ...

  3. 「SCOI2016」妖怪 解题报告

    「SCOI2016」妖怪 玄妙...盲猜一个结论,然后过了,事后一证,然后假了,数据真水 首先要最小化 \[ \max_{i=1}^n (1+k)x_i+(1+\frac{1}{k})y_i \] \ ...

  4. P4711 「化学」相对分子质量

    P4711 「化学」相对分子质量 给你一个字符串让你输出相对分子质量(弱智字符串模拟) 我比赛tm调了两个半小时啊QAQ 希望以后能增加代码力吧,纪念挂代码 Code #include<iost ...

  5. 「NOI2018」冒泡排序

    「NOI2018」冒泡排序 考虑冒泡排序中一个位置上的数向左移动的步数 \(Lstep\) 为左边比它大的数的个数,向右移动的步数 \(Rstep\) 为右边比它大的数的个数,如果 \(Lstep,R ...

  6. 「SDOI2005」区间

    「SDOI2005」区间 传送门 记录每一个位置作为左端点和右端点的出现次数,然后直接考虑差分即可. 参考代码: #include <cstdio> #define rg register ...

  7. 「POJ3613」Cow Relays

    「POJ3613」Cow Relays 传送门 就一个思想:\(N\) 遍 \(\text{Floyd}\) 求出经过 \(N\) 个点的最短路 看一眼数据范围,想到离散化+矩阵快速幂 代码: #in ...

  8. Python后端日常操作之在Django中「强行」使用MVVM设计模式

    扫盲 首先带大家了解一下什么是MVVM模式: 什么是MVVM?MVVM是Model-View-ViewModel的缩写. MVVM是MVC的增强版,实质上和MVC没有本质区别,只是代码的位置变动而已 ...

  9. 10月1日之后,你新建的GitHub库默认分支不叫「master」了

    从 2020 年 10 月 1 日开始,GitHub 上的所有新库都将用中性词「main」命名,取代原来的「master」,因为后者是一个容易让人联想到奴隶制的术语. 这个决定并不是最近才做出的.今年 ...

随机推荐

  1. Fiddler的一系列学习瞎记3

    Http: 不安全.可以很容易被拦截,或者其他的嗅探工具发现.怎么样做到安全?起码一下两点: 1.浏览器和we服务器之间的内容应该只有浏览器和web服务器能看到通信内容. 2.Http请求和Http的 ...

  2. 11Linux之软件包管理

    11Linux之软件包管理 目录 11Linux之软件包管理 11 软件包管理 11.1 软件包介绍 11.1.1 编程语言分类 11.1.2 三种安装包 11.2 rpm包管理 11.2.1 rpm ...

  3. 通过tuned-adm调整服务器的各种参数

    前言 centos7 服务器上面支持通过tuned进行统一的系统参数调整,以前我们可能会通过修改内核配置文件修改内核参数,通过echo去调整磁盘预读,等等很多调整会分散在各处 而系统实际上是可以通过一 ...

  4. SpringBean生命周期-Version-v5.1.0.RELEASE

    首先入口选定在org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons ...

  5. 微信公众号平台Url Token EncodingAESKey 注意点

    最近公司让我开发微信公众号平台扫码登录,同步用户信息于PC端,所做的过程当中遇到了一些坑,做完了就总结一下需要注意的点,如若大家开发过程中遇到同样的问题,可以借鉴! 第一:配置域名 作用:配置域名为了 ...

  6. scrapy学习之爬虫练习平台35

    前言 上一篇文章中爬取了爬虫练习平台的所有 ssr 网站,都是比较简单的,没有反爬措施,这次来爬一下后面的 spa 系列. 环境准备 这里沿用了上篇文章的环境和设置,就不重新搭建环境了. 开始爬取 s ...

  7. 面试官:你说你精通SpringBoot,你给我说一下类的自动装配吧

    ## 剖析@SpringBootApplication注解 创建一个SpringBoot工程后,SpringBoot会为用户提供一个Application类,该类负责项目的启动: ```@Spring ...

  8. 万字长文带你掌握Java数组与排序,代码实现原理都帮你搞明白!

    查找元素索引位置 基本查找 根据数组元素找出该元素第一次在数组中出现的索引 public class TestArray1 { public static void main(String[] arg ...

  9. [sql 注入] insert 报错注入与延时盲注

    insert注入的技巧在于如何在一个字段值内构造闭合. insert 报错注入 演示案例所用的表: MariaDB [mysql]> desc test; +--------+--------- ...

  10. Camtasia中对录制视频进行编辑——视觉效果

    视频剪辑对很多人来说是一件很头痛的事,因为对着屏幕一下一下的进行调整会让人十分的心烦,导致花费了时间但是剪辑出来的视频质量却并不高.或许是因为你没有选择一款合适的软件,因为一款高质量的软件往往会给人带 ...