【IOI2020国家集训队作业 Part 1】CF521E Cycling City

题目

题目描述
You are organizing a cycling race on the streets of the city. The city contains nn junctions, some pairs of them are connected by roads; on each road you can move in any direction. No two roads connect the same pair of intersections, and no road connects the intersection with itself.

You want the race to be open to both professional athletes and beginner cyclists, and that’s why you will organize the race in three nominations: easy, moderate and difficult; each participant will choose the more suitable nomination. For each nomination you must choose the route — the chain of junctions, consecutively connected by roads. Routes must meet the following conditions:

all three routes should start at the same intersection, and finish at the same intersection (place of start and finish can’t be the same);
to avoid collisions, no two routes can have common junctions (except for the common start and finish), and can not go along the same road (irrespective of the driving direction on the road for those two routes);
no route must pass twice through the same intersection or visit the same road twice (irrespective of the driving direction on the road for the first and second time of visit).
Preparing for the competition is about to begin, and you need to determine the routes of the race as quickly as possible. The length of the routes is not important, it is only important that all the given requirements were met.

输入格式
The first line contains two integers nn and mm ( 1<=n,m<=2·10^{5}1<=n,m<=2⋅10
5
) — the number of intersections and roads, respectively.

The following mm lines contain two integers — the numbers of the intersections connected by a road (the intersections are numbered starting with 1). It is guaranteed that each pair of intersections is connected by no more than one road, and no road connects the intersection to itself.

Please note that it is not guaranteed that you can get from any junction to any other one by using the roads.

输出格式
If it is possible to create the routes, in the first line print “YES”. In the next three lines print the descriptions of each of the three routes in the format " ll p_{1}p
1

… p_{l}p
l

", where ll is the number of intersections in the route, and p_{1},…,p_{l}p
1

,…,p
l

are their numbers in the order they follow. The routes must meet all the requirements specified in the statement.

If it is impossible to make the routes in accordance with the requirements, print NO.

题意翻译
给定一张 nn 个点 mm 条边的无向简单图。
问图中能否找到两个点,满足这两个点之间有至少三条完全不相交的简单路径。
n,m \le 2 \times 10^5n,m≤2×10
5
,图不保证连通。
输入输出样例
输入 #1复制
4 4
1 2
2 3
3 4
4 1
输出 #1复制
NO
输入 #2复制
5 6
1 2
1 3
1 4
2 5
3 5
4 5
输出 #2复制
YES
3 5 4 1
3 5 3 1
3 5 2 1

思路

首先建出 dfs 树,那么有解的充要条件是存在至少一条树边被至少两条返祖边覆盖,这显然可以树上差分判定。

若有解,考虑如何构造方案。

可以通过两次二分,每次判定使用树上差分,找到两条至少有一条树边被它们覆盖的返祖边。

在只保留这两条边的情况下构造方案即可

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 7;
int n, m, v[N], dfn[N], num, f[N], t, d[N];
vi e[N], ans[3];
pi p[N];

void dfs(int x) {
    dfn[x] = ++num;
    for (auto y : e[x])
        if (!dfn[y]) f[y] = x, dfs(y);
        else if (y != f[x] && dfn[y] < dfn[x]) p[++t] = mp(x, y);
}

void dfs1(int x) {
    v[x] = 1;
    for (auto y : e[x])
        if (f[y] == x) dfs1(y), d[x] += d[y];
}

void work(int o) {
    --d[p[o].se], ++d[p[o].fi];
}

bool ask(int l, int r) {
    for (int i = l; i <= r; i++) work(i);
    for (int i = 1; i <= n; i++) if (!v[i]) dfs1(i);
    bool ok = 0;
    for (int i = 0; i <= n; i++) ok |= d[i] > 1, d[i] = v[i] = 0;
    return ok;
}

int main() {
    rd(n), rd(m);
    for (int i = 1, x, y; i <= m; i++)
        rd(x), rd(y), e[x].pb(y), e[y].pb(x);
    for (int i = 1; i <= n; i++)
        if (!dfn[i]) dfs(i);
    if (!ask(1, t)) return prints("NO"), 0;
    else prints("YES");
    int l = 2, r = t;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (ask(1, mid)) r = mid;
        else l = mid + 1;
    }
    int R = l;
    l = 1, r = R - 1;
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (ask(mid, R)) l = mid;
        else r = mid - 1;
    }
    int L = l;
    work(L), work(R);
    for (int i = 1; i <= n; i++) if (!v[i]) dfs1(i);
    int Y = 0;
    for (int i = 1; i <= n; i++)
        if (d[i] == 2 && dfn[i] > dfn[Y]) Y = i;
    int X = Y;
    ans[0].pb(X);
    while (d[X] == 2) ans[0].pb(X = f[X]);
    reverse(ans[0].begin(), ans[0].end());
    for (int i = 1; i < 3; i++) {
        int Z = X, o = i == 1 ? L : R;
        ans[i].pb(Z);
        while (Z != p[o].se) ans[i].pb(Z = f[Z]);
        ans[i].pb(Z = p[o].fi);
        while (Z != Y) ans[i].pb(Z = f[Z]);
    }
    for (int i = 0; i < 3; i++) {
        print(ans[i].size(), ' ');
        for (auto x : ans[i]) print(x, ' ');
        prints("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值