[luogu p2783]有机化学之神 (最水黑题)

Posted djhsbdb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu p2783]有机化学之神 (最水黑题)相关的知识,希望对你有一定的参考价值。

题目背景

XS中学化学竞赛组教练是一个酷爱炉石的人。

有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹。

然而你的化竞基友却向你求助了。

“第1354题怎么做”<--手语 他问道。

题目描述

你翻到那一题:给定一个烃,只含有单键(给初中生的一个理解性解释:就是一堆碳用横线连起来,横线都是单条的)。

然后炎魔之王拉格纳罗斯用他的火焰净化了一切环(???)。所有的环状碳都变成了一个碳。如图所示。

技术分享图片

然后指定多组碳,求出它们之间总共有多少碳。如图所示(和上图没有关系)。

技术分享图片

但是因为在考试,所以你只能把这个答案用手语告诉你的基友。你决定用二进制来表示最后的答案。如图所示(不要在意,和题目没有什么没关系)。

技术分享图片

输入输出格式

输入格式:

 

第一行两个整数n,m.表示有n个点,m根键

接下来m行每行两个整数u,v表示u号碳和v号碳有一根键

接下来一个整数tot表示询问次数

接下来tot行每行两个整数,a,b表示询问的两个碳的编号

 

输出格式:

 

共tot行

每行一个二进制数

输入输出样例

输入样例:
3 2
1 2
2 3
2
1 2
2 3
输出样例: 
10
10
双连通分量+lca求距离
不知道为什么是黑题,连我这种小蒟蒻都会的。。
主要是tarjan和lca求距离以及缩点重建图
直接上代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack> 

using namespace std;

inline int read(){
    int x=0; bool f=1; char c=getchar();
    while(!isdigit(c)){if(c==-)f=0;c=getchar();}
    while(isdigit(c)){x=x*10+c-0;c=getchar();}
    if(!f)return 0-x;
    return x;
}

const int M=10010;
const int N=50010;

vector<int>e[M];//无权图,直接存vector 
vector<int>g[M];

int n,m,tot,dfn[M],low[M],vis[M],color[M],tim,megumi,x[N],y[N],f[M][25],depth[M],QAQ;

stack<int>s;

inline void tarjan(int u,int fa){
    dfn[u]=low[u]=++tim;
    s.push(u);
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if(v==fa)continue;//双连通分量 
        if(!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(!color[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        ++megumi;
        while(s.top()!=u){
            color[s.top()]=megumi;
            s.pop();
        }
        color[s.top()]=megumi;
        s.pop();
    }
}

inline void rebuild(){
    for(int i=1;i<=m;i++){
        if(color[x[i]]^color[y[i]])
            g[color[x[i]]].push_back(color[y[i]]),g[color[y[i]]].push_back(color[x[i]]);//必须是color[x[i]],卡了半个小时qwq 
    }
}

inline void dfs(int u,int fa){
    if(vis[u])return ;
    vis[u]=1;
    depth[u]=depth[fa]+1;
    for(int i=1;i<=20;i++){
        f[u][i]=f[f[u][i-1]][i-1];
    }
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==fa)continue;
        f[v][0]=u;
        dfs(v,u);
    }
}

inline int lca(int a,int b){
    if(depth[a]<depth[b]) swap(a,b);
    for(int i=20;i>=0;i--){
        if(depth[f[a][i]]>=depth[b])
            a=f[a][i];
    }
    if(a==b)return a;
    for(int i=20;i>=0;i--){
        if(f[a][i]!=f[b][i]){
            a=f[a][i],b=f[b][i];
        }
    }
    return f[a][0];
}

inline void print(int x){//打印二进制 
    if(!x)return ;
    print(x>>1);
    printf("%d",x&1);
}

int main(){
//    freopen("haha.in","r",stdin);
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        x[i]=read(),y[i]=read();
        e[x[i]].push_back(y[i]);
        e[y[i]].push_back(x[i]);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i])tarjan(i,i);
    }
    rebuild();
    megumi++;
    for(int i=1;i^megumi;i++){
        if(!vis[i])dfs(i,i);
    }
    tot=read();
    for(int i=1;i<=tot;i++){
        int x,y;
        x=read(),y=read();
        int l=lca(color[x],color[y]);
        print(depth[color[x]]-depth[l]+depth[color[y]]-depth[l]+1);
        printf("
");
    }
//    fclose(stdin);
    return QAQ;
}

 







以上是关于[luogu p2783]有机化学之神 (最水黑题)的主要内容,如果未能解决你的问题,请参考以下文章

p2783有机化学之神偶尔会做作弊

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

Luogu 4240:毒瘤之神的考验

Luogu P2382 化学分子式 (模拟)

P4240 毒瘤之神的考验

luogu P4711 「化学」相对分子质量 题解