zoukankan      html  css  js  c++  java
  • BZOJ2791 Rendezvous

    Description
    给定一个n个顶点的有向图,每个顶点有且仅有一条出边。
    对于顶点i,记它的出边为(i, a[i])
    再给出q组询问,每组询问由两个顶点ab组成,要求输出满足下面条件的xy
    1. 从顶点a沿着出边走x步和从顶点b沿着出边走y步后到达的顶点相同。
    2. 在满足条件1的情况下max(x,y)最小。
    3. 在满足条件12的情况下min(x,y)最小。
    4. 在满足条件123的情况下x>=y
    如果不存在满足条件1xy,输出-1 -1
    Input
    第一行两个正整数nq (n,q<=500,000)
    第二行n个正整数a[1],a[2],...,a[n] (a[i]<=n)
    下面q行,每行两个正整数a,b (a,b<=n),表示一组询问。
    Output
    输出q行,每行两个整数。



    思路:其实我觉得基环树题就是暴力模拟题……先找环,然后有多种情况,在环上某点的同一子树下,在环上不同子树下,不在同一联通块内,一一处理即可

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 5e5 + 10;
     
    int head[N], now;
    struct edges{
        int to, next, w;
    }edge[N<<1];
    void add(int u, int v, int w){ edge[++now] = {v, head[u], w}; head[u] = now;}
    void read(int &x){
        int f=1;x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        x*=f;
    }
     
    int n, q, dfn[N], sz, pre[N], tot, c[N], dict[N], bel[N], fa[N][22], dep[N], pos[N];
    vector<int> cir[N];
    void fcur(int x){
        dfn[x] = ++sz; bel[x] = tot;
        for(int i = head[x]; i; i = edge[i].next){
            int v = edge[i].to;
            if(v == pre[x]) continue;
            if(dfn[v]){
                if(dfn[v] < dfn[x]) continue;
                cir[tot].push_back(x); c[x] = tot;
                for(; x != v; v = pre[v]){
                    cir[tot].push_back(v), c[v] = tot;
                }
            }else pre[v] = x, fcur(v);
        }
        return ;
    }
     
    void dfs(int x, int father, int root){
        dict[x] = root; fa[x][0] = father;
        for(int i = head[x]; i; i = edge[i].next){
            int v = edge[i].to;
            if(v == father || c[v]) continue;
            dep[v] = dep[x] + 1;
            dfs(v, x, root);
        }
    }
    int LCA(int u,int v){
        if(dep[u]<dep[v]) swap(u,v);
        int k=dep[u]-dep[v];
        for(int i=0;i<=20;i++)
          if((1<<i)&k) u=fa[u][i];
        if(u==v) return u;
        for(int i=20;i>=0;i--)
          if(fa[u][i]!=fa[v][i])
            u=fa[u][i],v=fa[v][i];
        return fa[u][0];
    }
    void dfs2(int x, int step){
        pos[x] = step;
        for(int i = head[x]; i; i = edge[i].next){
            int v = edge[i].to;
            if(edge[i].w && !pos[v]) dfs2(v, step + 1);
        }
    }
    int main(){
        read(n), read(q);
        int x, y;
        for(int i = 1; i <= n; i++){
            read(x);
            add(i, x, 1), add(x, i, 0);
        }
        for(int i = 1; i <= n; i++){
            if(!dfn[i]){
                sz = 0;  tot++;
                fcur(i);
            }
        }
        for(int i = 1; i <= tot; i++){
            dfs2(cir[i][0], 1);
            for(int j = 0; j < cir[i].size(); j++){
                x = cir[i][j];
                dict[x] = x;
                dfs(x, x, x);
            }
        }
        for(int j = 0; j <= 20; j++)
          for(int i = 1; i <= n; i++)
              fa[i][j + 1] = fa[fa[i][j]][j];
        while(q--){
            scanf("%d%d", &x, &y);
            if(bel[x] != bel[y]){
                puts("-1 -1");  continue;
            }else if(dict[x] == dict[y]){
                int lca = LCA(x, y);
                printf("%d %d
    ", dep[x] - dep[lca], dep[y] - dep[lca]);
            }else{
                int rt1 = dict[x], rt2 = dict[y], siz = cir[bel[x]].size();
                int s1 = dep[x] - dep[rt1], s2 = dep[y] - dep[rt2];
                int k1, k2;
                if(pos[rt1] < pos[rt2])  k1 = pos[rt2] - pos[rt1], k2 = siz - k1;
                else k2 = pos[rt1] - pos[rt2], k1 = siz - k2;
                int tmp1 = s1 + k1, tmp2 = s2 + k2;
                if(max(tmp1, s2) != max(s1, tmp2)){
                    if(max(tmp1, s2) > max(s1, tmp2)) printf("%d %d
    ", s1, tmp2);
                    else printf("%d %d
    ", tmp1, s2);
                    continue;
                }
                else if(min(tmp1, s2) != min(s1, tmp2)){
                    if(min(tmp1, s2) > min(s1, tmp2)) printf("%d %d
    ", s1, tmp2);
                    else printf("%d %d
    ", tmp1, s2);
                    continue;
                }
                else{
                    if(tmp1 >= s2) printf("%d %d
    ", tmp1, s2);
                    else printf("%d %d
    ", s1, tmp2);
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Nginx配置SSL证书实现https访问及端口映射
    Nginx动静分离实现
    Nginx+Keepalived实现高可用部署
    Linux环境Nginx反向代理实现负载均衡
    Linux环境Nginx安装
    merlin矿池被攻击详情
    CVE-2021-26855 Exchange Server RCE
    C语言博客作业04--数组
    第四次作业
    SpringBoot集成多数据源-----基于数据库维护
  • 原文地址:https://www.cnblogs.com/Rorshach/p/8724885.html
Copyright © 2011-2022 走看看