首页 > 其他分享 >题解 CF1873H【Mad City】

题解 CF1873H【Mad City】

时间:2023-09-28 10:13:38浏览次数:39  
标签:City return int 题解 rep fa ext Mad dis

其他题解怎么又 Tarjan 又 Dijkstra 的,这是 div4H 的样子吗,来个简单好写的做法。

题面里的人名太复杂了,本题解中称为警察和小偷。

注意到,如果小偷成功到达了环上,那么一定不会被警察抓到。因为小偷知道警察下一步会走到哪里,他可以执行相同的操作(顺时针/逆时针/静止),使得他和警察之间的距离不变。

那么问题就是警察是否可以在小偷到达环上之前就蹲守在小偷的必经之路上,也就是环上离小偷最近的那个点。如果我们知道这个点,还知道任意两个点之间的距离,那么判断一下哪个更大就解决了。

下面是比较简单的实现方法。

维护一个并查集记录任意两个点是否连通,在加边的过程中,如果两端未连通,就加这条边,否则不加边并把两个端点记录为 \(ext_u,ext_v\)。在处理完所有边后,我们得到了原基环树的一棵生成树,以及被删掉的那条环上的边的两端点。

通过树上倍增实现生成树的 LCA,然后使用树上差分可以求得生成树上任意两点间距离,设为 \(dis_T(u,v)\)。考虑原基环树上两点间距离是什么,有两种情况,一种是只走生成树边,另一种是经过了被删除的边。前者即 \(dis_T(u,v)\),后者根据经过方向不同又有两种情况,分别是 \(dis_T(u,ext_u)+1+dis_T(ext_v,v)\) 和 \(dis_T(u,ext_v)+1+dis_T(ext_u,v)\),意思是 \(u\stackrel{*}{\to} ext_u\to ext_v\stackrel{*}{\to} v\) 和 \(u\stackrel{*}{\to} ext_v\to ext_u\stackrel{*}{\to} v\) 两条路径。因此,原基环树上两点间距离 \(dis_G(u,v)=\min\{dis_T(u,v),dis_T(u,ext_u)+1+dis_T(ext_v,v),dis_T(u,ext_v)+1+dis_T(ext_u,v)\}\)。

标记环上的点的方法是求出 \(ext_u\) 和 \(ext_v\) 的 LCA,并暴力跳父亲标记 \(ext_u\) 和 \(ext_v\) 之间的所有点。求环上离小偷最近的点只需要枚举所有点 \(u\),判断是否在环上,如果在环上就取出 \(dis_G(u,b)\) 最小的点,记作 \(pos\)。然后比较 \(dis_G(pos,a)\) 和 \(dis_G(pos,b)\) 的大小关系即可得到答案。

时间复杂度 \(O(n\log n)\)。

// LUOGU_RID: 126418248
// Problem: H. Mad City
// Contest: Codeforces - Codeforces Round 898 (Div. 4)
// URL: https://codeforces.com/contest/1873/problem/H
// Memory Limit: 256 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=(y);x<=(z);x++)
#define per(x,y,z) for(int x=(y);x>=(z);x--)
#define debug(format...) fprintf(stderr, format)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
using namespace std;
typedef long long ll;

mt19937 rnd(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
int randint(int L, int R) {
    uniform_int_distribution<int> dist(L, R);
    return dist(rnd);
}

template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}

const int N = 2e5+5;

int T, n, a, b, ext_u, ext_v, dis[N], fa[19][N], cyc[N];
vector<int> e[N];

struct Dsu {
    int fa[N];
    void init(int x) {rep(i, 1, x) fa[i] = i;}
    int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
    bool same(int x, int y) {return find(x) == find(y);}
    bool merge(int x, int y) {
        if(same(x, y)) return false;
        x = find(x); y = find(y);
        fa[x] = y;
        return true;
    }
}dsu;

void dfs(int u, int f) {
    dis[u] = dis[f] + 1;
    fa[0][u] = f;
    rep(i, 1, 18) fa[i][u] = fa[i-1][fa[i-1][u]];
    for(int v : e[u]) if(v != f) dfs(v, u);
}

inline int LCA(int u, int v) {
    if(dis[u] < dis[v]) swap(u, v);
    per(i, 18, 0) if(dis[fa[i][u]] >= dis[v]) u = fa[i][u];
    if(u == v) return u;
    per(i, 18, 0) if(fa[i][u] != fa[i][v]) u = fa[i][u], v = fa[i][v];
    return fa[0][u];
}

inline int disT(int u, int v) {
    return dis[u] + dis[v] - 2 * dis[LCA(u, v)];
}

inline int disReal(int u, int v) {
    return min({disT(u, v), disT(u, ext_u) + disT(ext_v, v) + 1, disT(u, ext_v) + disT(v, ext_u) + 1});
}

int main() {
    for(scanf("%d", &T); T; T--) {
        scanf("%d%d%d", &n, &a, &b);
        dsu.init(n);
        rep(i, 1, n) {
            int u, v;
            scanf("%d%d", &u, &v);
            if(dsu.same(u, v)) {
                ext_u = u;
                ext_v = v;
            }
            else {
                e[u].push_back(v);
                e[v].push_back(u);
                dsu.merge(u, v);
            }
        }
        dfs(1, 0);
        int p = LCA(ext_u, ext_v);
        for(int u = ext_u; u != p; u = fa[0][u]) cyc[u] = 1;
        for(int v = ext_v; v != p; v = fa[0][v]) cyc[v] = 1;
        cyc[p] = 1;
        int d = n, pos = 0;
        rep(i, 1, n) if(cyc[i]) if(disReal(b, i) < d) d = disReal(b, i), pos = i;
        puts(d < disReal(a, pos) ? "YES" : "NO");
        // clear
        rep(i, 1, n) {
            dis[i] = cyc[i] = 0;
            rep(j, 0, 18) fa[j][i] = 0;
            e[i].clear();
        }
        ext_u = ext_v = 0;
    }
    return 0;
}

标签:City,return,int,题解,rep,fa,ext,Mad,dis
From: https://www.cnblogs.com/ruierqwq/p/CF-1873H.html

相关文章

  • [ARC124C] LCM of GCDs 题解
    题面给定\(N\)个正整数对\((a_i,b_i)\)和两个初始为空的集合\(S,T\),你可以选择将每个数对的两个元素划分到两个不同的集合中。求\[\max\operatorname{lcm}(\gcd\limits_{x\inS}x,\gcd\limits_{y\inT}y)\](\(1\leN\le50,1\lea_i,b_i\le10^9\))。题解首先,......
  • P4370 [Code+#4] 组合数问题2-题解-有关对数的小技巧
    20230927P4370[Code+#4]组合数问题2-solStatement传送门给你两个数\(n,k\),要求对于组合数\(C_{a}^{b}\)找到任何\(k\)个,让他们的和最大,且组合数各不相同,当且仅当\(a,b\)不完全相同时,组合数不同。Solution首先,很容易发现\(C_{n}^{m}\gtc_{n-1}^{m}\),所......
  • CF364D Ghd 题解
    CF364DGhd题解题目大意给定一个长度为\(n\)的序列,你需要从中选出一个元素个数不少于\(\left\lceil{\frac{n}{2}}\right\rceil\)的子序列,使得这个子序列中所有元素的\(\gcd\)最大。分析数据范围吓人。\(10^6\),但是根本想不到什么\(O(n\logn)\)或\(O(n)\)的算法......
  • [ARC125B] Squares 题解
    题意给定正整数\(N\),求满足如下条件的正整数对\((x,y)\)的数量:\(1\lex,y\leN\)\(x^2-y\)为完全平方数(\(0\)也是完全平方数)(\(1\leN\le10^{12}\))。题解因为\(x^2-y\)为完全平方数,设其为\(z^2\),那么有\[\begin{aligned}x^2-y=z^2\\\end{al......
  • [题解] Codeforces Round 900(Div.3) E~F
    CodeforcesRound900(Div.3)E~FE.Iva&Pav因为按位与的结果不会随着越多数字的增加而增加,因此我们可以利用这个性质二分出右端点,只需要一个可以查询区间的数据结构即可。或者是按位考虑第\(i\)个数字的第\(k\)位,后缀最近的\(0\)的位置,按位考虑也可以。但是这题使用二分......
  • ACAM 学习笔记 | 附 YbtOJ 全部题解
    怎么有人现在才学ACAM呢。好像比SAM简单挺多啊,也不记得当时是哪里看不懂。AC自动机(✔)自动AC机(✘)概述ACAM(Aho–CorasickAutomaton),是用来解决多模式串匹配的字符串算法。它的结构是个DAG,其中点表示状态,边表示转移。这一点上各种自动机都是相同的。具体来说,可以感性......
  • [题解]CF1878E Iva & Pav
    CF是没题考了吧,每场都出二进制拆位。思路首先我们可以二分\(r\),因为\(r\)越大,按位与一定只会小于等于\(r\)小的情况。那么,我们可以用\(num_{i,j}\)记录\(a_j\)第\(i\)位的二进制情况。如果我们对\(num_{i,j}\)做一个前缀和,如果\(num_{i,r}-num_{i,l-1}=r......
  • 安装 SonarQube后sonarqube-sonarqube无法启动的问题解决
    1.前言我的环境:k8s集群(version1.23.6),安装了Kubesphere(versionv3.4)作为可视化界面,最近想要推动团队走CICD,于是在Kubesphere中启用了devops组件,参考:https://kubesphere.io/zh/docs/v3.4/pluggable-components/devops/。组件安装完成后,需要将Sonarqube集成到流水线中,于是又安装......
  • luogu P4819 [中山市选] 杀人游戏 题解 【强连通分量+缩点】
    目录题目链接思路分析代码题目链接P4819思路分析首先考虑这道题的连通性。容易发现这种类型的题目会容易产生环形的状态转移。假设我们知道了其中的一个点是否是黑白点,那么我们就可以知道所有点是否是黑白点。容易陷入一个误区:我们只能通过一个点知道他所相邻的最直接的点,如何......
  • CF1878 A-G 题解
    前言赛时代码可能比较难看。A判定\(a\)中是否有\(k\)即可。赛时代码B奇怪的构造题。令\(a_1=1,a_2=3\),其他项由上一项加一开始枚举判定可行性即可,可以简单证明时间复杂度为\(O(n)\)。赛时代码C容易发现当\(x\in\left[\dfrac{k(k+1)}{2},\dfrac{k(2n-k+1)}{2}\ri......