• [洛谷P2783]有机化学之神偶尔会做作弊


    第一次做出来黑题祭

    虽然感觉难度其实并不到黑题的难度

    题解:

    其实这道题并没用什么特别的知识,只是Tarjan求双联通分量和LCA的结合。

    所以,我们可以很显然的发现(如此恶劣的词汇,逃

    这道题其实就是给你一个无向图,其中一个点双联通分量算作一个点,询问两个点之间(包括这两个点)有多少点(注意重边不需要缩点)。注意这里的图是无向图,所以我们如果用单纯的Tarjan求强连通分量,就会得到WA的好成绩。

    因此 --->我们用Tarjan双联同分量进行缩点,特判一下如果是他的父亲,就不执行(去除重边的影响),然后(O(m))重建图,跑一边LCA求距离就好了

    这里有坑:

    1.没有关注重边。
    2.查询写成原图中的编号,应为所在联通块的编号。
    3.数据略卡常,要用快读进行输入。

    CODE:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<stack>
    
    using namespace std;
    
    #define N 10010
    #define M 100010
    
    int head[N],dfn[N],low[N];
    int idx,link[N],tot1,fa[N][25];
    int belong[N],m,n,tot2;
    int depth[N],xx[M],yy[M];
    bool vis[N];
    stack<int> st;
    struct Edge{ 
        int from,to; 
    }e[M*2],edge[M*2];
    
    inline int read() {
       int s = 0,w = 1;
       char ch =getchar();
       while(ch <= '0' || ch > '9') {if(ch == '-') w = -1 ; ch = getchar();}
       while(ch >= '0' && ch <= '9') {s = s * 10 + ch - '0',ch = getchar();}
       return s * w;
    }
    inline void add_edge(int u,int v) {
        e[++tot1].from = v;
        e[tot1].to = head[u];
        head[u] = tot1;
    }
    int cnt;
    void Tarjan(int u,int from) {
        low[u] = dfn[u] = ++idx; 
        st.push(u); 
        vis[u] = true;
        for(int i = head[u] ; i ; i = e[i].to) {
            int v = e[i].from;
            if(v == from) continue;
            if(dfn[v] == -1) {
                Tarjan(v,u);
                low[u] = min(low[u],low[v]);
            } else if(vis[v]) 
                low[u] = min(low[u],dfn[v]);
        }
        if(dfn[u] == low[u]) {
            ++cnt;
            while(1){
                int v = st.top();
                st.pop();
                vis[v] = 0; 
                belong[v]=cnt;
                if(v == u) break;
            }
        }
    }
    inline void add_edge2(int u,int v) {
        edge[++tot2].from = v;
        edge[tot2].to = link[u];
        link[u] = tot2;
    }
    void dfs(int u,int from,int deepth) {
        depth[u] = deepth; 
        fa[u][0] = from;
        for(int i = link[u] ; i ; i = edge[i].to) {
            int v = edge[i].from;
            if(v != from) dfs(v,u,deepth+1);
        }
    }
    int LCA(int u,int v) {
        if(depth[u] < depth[v]) swap(u,v);
        for(int j = 0 ; j <= 22 ; j++)
            if((depth[u] - depth[v]) & (1<<j)) 
                u = fa[u][j];
        if(u == v) return u;
        for(int i = 22 ; i >= 0 ; i--)
            if(fa[u][i] != fa[v][i]) {
                u = fa[u][i];
                v = fa[v][i];
            }
        return fa[u][0];
    }
    int ans[28000];
    int print(int n) {
        int cur =0;
        if(n == 0) {  cout<<'0';return 0; }
        if(n < 0) { putchar('-');n=0-n; }
        while(n) {
            int p = n % 2;
            ans[++cur] = p;
            n /= 2;
        }
        for(int i = cur ; i >= 1 ; i--) 
            printf("%d",ans[i]);
        cout<<endl;
    }
    
    int main() {
        n = read();
        m = read();
        memset(dfn,-1,sizeof(dfn) );
        memset(low,-1,sizeof(low) );
        for(int i = 1 ; i <= m ; i++) {
            int u,v;
            u= read(),v = read();
            xx[i] = u,yy[i] = v;
            add_edge(u,v);
            add_edge(v,u);
        }
        for(int i = 1 ; i <= n ; i++)
            if(dfn[i] == -1)
                Tarjan(i,-1);
        for(int i = 1 ; i <= m ; i++) {
            if(belong[xx[i]] != belong[yy[i]]) {
                add_edge2(belong[xx[i]],belong[yy[i]]);
                add_edge2(belong[yy[i]],belong[xx[i]]);
            }
        }
        dfs(belong[1],belong[1],0);
        for(int j = 1 ; j <= 22 ; j++)
            for(int i = 1 ; i <= cnt ; i++)
                fa[i][j] = fa[fa[i][j - 1]][j - 1];
        int T;
        T = read();
        while(T--) {
            int u,v;
            scanf("%d%d",&u,&v);
            int num = LCA(belong[u],belong[v]);
            print(depth[belong[u]] + depth[belong[v]] - depth[num] - depth[num] + 1);
        }
        return 0;
    }
    
  • 相关阅读:
    Swift流程控制之循环语句和判断语句详解
    框架内的文件集合
    十分钟让你明白Objective-C的语法(和Java、C++的对比)
    Swift版音乐播放器(简化版),swift音乐播放器
    通过数字电视通过宽带网络取代互联网电视机顶盒应用
    JS学习笔记-OO创建怀疑的对象
    如果不能显示真正的考验个别车型toast问题解决
    swift 它们的定义TabBarItem
    NSUserDefaults API简单的介绍和使用英文文件
    FZU 1686 龙之谜 重复覆盖
  • 原文地址:https://www.cnblogs.com/Repulser/p/9621783.html
Copyright © 2020-2023  润新知