zoukankan      html  css  js  c++  java
  • Rendezvous

    题面

    给定一个n个顶点的有向图,每个顶点有且仅有一条出边。

    对于顶点i,记它的出边为(i, a[i])。

    再给出q组询问,每组询问由两个顶点a、b组成,要求输出满足下面条件的x、y:

    从顶点a沿着出边走x步和从顶点b沿着出边走y步后到达的顶点相同。
    在满足条件1的情况下max(x,y)最小。
    在满足条件1和2的情况下min(x,y)最小。
    在满足条件1、2和3的情况下x>=y。
    如果不存在满足条件1的x、y,输出-1 -1。

    输入格式
    第一行两个正整数n和q。

    第二行n个正整数a[1],a[2],…,a[n]。

    下面q行,每行两个正整数a,b,表示一组询问。

    输出格式
    输出q行,每行两个整数。

    数据范围

    n,q≤500000,
    a[i]≤n,
    a,b≤n
    

    输入样例:

    12 5
    4 3 5 5 1 1 12 12 9 9 7 1
    7 2
    8 11
    1 2
    9 10
    10 5
    

    输出样例:

    2 3
    1 2
    2 2
    0 1
    -1 -1
    

    题解

    这道题和那道基环树森林是类似的, 从在子树上 和 在环上 考虑

    先用dfs, 跑同一个基环树上的所有点, 并找出环

    我们使用倍增的方法, 处理环上的每棵子树

    对于两个节点, 且二者不在同一颗基环树上, 明显 -1, -1

    然后就是倍增找父节点,

    直接通过 较大深度的节点 向上走 走到x 的, x y同一颗子树, 答案明显 二者深度分别减去 lca深度

    然后是 两者在同意深度, 向上同时走

    1.最后按通常情况 f[x][0], 应该是lca, 但是我们由于x, y可能在不同的子树上,

    所以当 f[x][0] != 0, 是 lca = f[x][0], 答案和上一样, x y同一颗子树

    2.f[x][0] == 0, 明显 x, y都走到了自己所在子树的根节点, 也就是环上

    那么按照题意, 选择是让 x -> y, 还是 y -> x, 计算答案即可

    #include <bits/stdc++.h>
    #define all(n) (n).begin(), (n).end()
    #define se second
    #define fi first
    #define pb push_back
    #define mp make_pair
    #define sqr(n) (n)*(n)
    #define rep(i,a,b) for(int i=a;i<=(b);++i)
    #define per(i,a,b) for(int i=a;i>=(b);--i)
    #define IO ios::sync_with_stdio(0); cin.tie(0);
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> PII;
    typedef pair<ll, ll> PLL;
    typedef vector<int> VI;
    typedef double db;
    
    const int N = 5e5 + 5;
    
    int n, m, _, k, t;
    int h[N], to[N << 1], ne[N << 1], tot;
    int f[N][20], dep[N];
    int a[N], idx[N], idcnt, idc[N], sizc[N];
    int cir[N], cid;
    bool v[N];
    
    void add(int u, int v) {
        ne[++tot] = h[u]; h[u] = tot; to[tot] = v;
    }
    
    void bfs(int s) {
        queue<int> q; q.push(s); dep[s] = 1;
        while (!q.empty()) {
            int x = q.front(); q.pop();
            for (int i = h[x]; i; i = ne[i]) {
                if (!(i & 1)) continue;
                int y = to[i];
                if (v[y] || dep[y]) continue;
                dep[y] = dep[x] + 1; f[y][0] = x;
    
                for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
                q.push(y);
            }
        }
    }
    
    PII lca(int x, int y) {
        if (idx[x] != idx[y]) return { -1, -1 };
        int a = x, b = y; bool flag = 0;
    
        if (dep[x] > dep[y]) swap(x, y), flag = 1;
        per(i, t, 0) if (dep[f[y][i]] >= dep[x]) y = f[y][i];
        if (x == y) return { dep[a] - dep[x], dep[b] - dep[x] };
    
        per(i, t, 0) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
        if (f[x][0]) return { dep[a] - dep[f[x][0]], dep[b] - dep[f[x][0]] };
    
        x = idc[x], y = idc[y];
        if (flag) swap(y, x);
        PII p = { dep[a] - 1, dep[b] - 1 };
        int bd = y > x ? sizc[idx[a]] - y + x : x - y;
        int ad = y > x ? y - x : sizc[idx[a]] - x + y;
    
        if (max(p.fi + ad, p.se) < max(p.se + bd, p.fi)) p.fi += ad;
        else if (max(p.se + bd, p.fi) < max(p.fi + ad, p.se)) p.se += bd;
        else if (min(p.se, p.fi + ad) > min(p.fi, p.se + bd)) p.se += bd;
        else p.fi += ad;
    
        return p;
    }
    
    int dfsc(int u, int bian) {
        idx[u] = idcnt; int s = 0;
        for (int i = h[u]; i; i = ne[i]) {
            int y = to[i];
            if (bian == i + 1 >> 1 || v[y]) continue;
            if (!idx[y]) s = max(s, dfsc(y, i + 1 >> 1));
            else cir[idc[s = u] = ++cid] = u, v[u] = 1;
        }
        return s;
    }
    
    void work(int u) {
        cid = 0; ++idcnt;
        for (u = a[dfsc(u, 0)];u != cir[1]; u = a[u]) 
            cir[idc[u] = ++cid] = u, v[u] = 1;
        sizc[idcnt] = cid;
        rep(i, 1, cid) bfs(cir[i]);
    }
    
    int main() {
        IO; cin >> n >> m;
        t = log2(n - 1) + 1;
        rep(i, 1, n) cin >> a[i], add(a[i], i), add(i, a[i]);
        rep(i, 1, n) if (!idx[i]) work(i);
    
        rep(i, 1, m) {
            int x, y; cin >> x >> y;
            PII p = lca(x, y);
            cout << p.fi << ' ' << p.se << '
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    南阳ACM 题目811:变态最大值 Java版
    南阳ACM 题目811:变态最大值 Java版
    南阳ACM 题目517:最小公倍数 Java版
    南阳ACM 题目517:最小公倍数 Java版
    Jquery学习总结(4)——高效Web开发的10个jQuery代码片段
    Mysql学习总结(34)——Mysql 彻底解决中文乱码的问题
    MyBatis学习总结(19)——Mybatis传多个参数(三种解决方案)
    Git学习总结(10)——git 常用命令汇总
    Spring MVC学习总结(7)——Spring MVC整合Ehcache缓存框架
    Mysql学习总结(33)——阿里云centos配置MySQL主从复制
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/13584425.html
Copyright © 2011-2022 走看看