[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("\n");
    }
//    fclose(stdin);
    return QAQ;
}

原文地址:https://www.cnblogs.com/djhsbdb/p/9868545.html

时间: 2024-10-14 11:18:54

[luogu p2783]有机化学之神 (最水黑题)的相关文章

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

题目传送门 啦啦啦,发个文纪念一下第一道在洛谷上A的黑题,一次性就过真是无比舒服-(虽然某些大佬说这题有点水……)题目其实思路不难,Tarjan缩点+LCA,不过因为是无向边,所以在Tarjan的时候做点标记就行了,不过第四个点会被卡,用vector存边就可以A掉了.另外输出用二进制这个应该没什么好说的. 下面放代码: #include<cmath> #include<stack> #include<vector> #include<cstdio> #inc

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

题目背景 LS中学化学竞赛组教练是一个酷爱炉石的人. 有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹. 然而你的化竞基友却向你求助了. “第1354题怎么做”<--手语 他问道. 题目描述 你翻到那一题:给定一个烃,只含有单键(给初中生的一个理解性解释:就是一堆碳用横线连起来,横线都是单条的). 然后炎魔之王拉格纳罗斯用他的火焰净化了一切环(???).所有的环状碳都变成了一个碳.如图所示. 然后指定多组碳,求出它们之间总共有多少碳.如图所示(和上图没有关系). 但是因为在考试,

8.2/baltic神(水)题

bzoj1334: Description N个政党要组成一个联合内阁,每个党都有自己的席位数. 现在希望你找出一种方案,你选中的党的席位数要大于总数的一半,并且联合内阁的席位数越多越好. 对于一个联合内阁,如果某个政党退出后,其它党的席位仍大于总数的一半,则这个政党被称为是多余的,这是不允许的. Input 第一行给出有多少个政党.其值小于等于300 下面给出每个政党的席位数.总席位数小于等于 100000 Output 你的组阁方案中最多能占多少个席位. 背包dp.一开始想着贪心贪心...后

HDU-1037-Keep on Truckin&#39;(HDU最水的题没有之一,为了练英语就来吧)

Keep on Truckin' Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 10324    Accepted Submission(s): 7147 Problem Description Boudreaux and Thibodeaux are on the road again . . . "Boudreaux, we ha

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

Description 你翻到那一题:给定一个烃,只含有单键(给初中生的一个理解性解释:就是一堆碳用横线连起来,横线都是单条的). 然后炎魔之王拉格纳罗斯用他的火焰净化了一切环(???).所有的环状碳都变成了一个碳.如图所示. 然后指定多组碳,求出它们之间总共有多少碳.如图所示(和上图没有关系). 但是因为在考试,所以你只能把这个答案用手语告诉你的基友.你决定用二进制来表示最后的答案.如图所示(不要在意,和题目没有什么没关系). Input 第一行两个整数n,m.表示有n个点,m根键 接下来m行

luogu P1774 最接近神的人_NOI导刊2010提高(02)

题目描述 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案.而石门上方用古代文写着"神的殿堂".小FF猜想里面应该就有王室的遗产了.但现在的问题是如何打开这扇门-- 仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的.而最聪明的人往往通过一种仪式选拔出来.仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即交换序列中相邻的两个元素.而用最少的交换次数使原

【Virtual Judge】G - 一般水的题2-Approximating a Constant Range

Description When Xellos was doing a practice course in university, he once had to measure the intensity of an effect that slowly approached equilibrium. A good way to determine the equilibrium intensity would be choosing a sufficiently large number o

我的CodeF水A题之路

Codeforces Round #359 (Div. 2) A. Free Ice Cream 题目链接:http://www.codeforces.com/problemset/problem/686/A 题意:N个人在排队,一开始店主有M个冰淇凌,队伍中第i个人可能是一个送冰激凌的工人,他会带给店主+A[i]个冰淇凌,也可能是一个小朋友,他想要-A[i]个冰淇凌,当排到一个小朋友的时候,如果店主现在手里的冰淇凌数量能满足他,那么就满足他,不然小朋友就会一个冰淇凌也不拿失望的离开. ques

codevs 1360 xth砍树 线段树不能再水的题了

连标记都不用打.. #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=200003; const double mo=3.14; double sum[N<<2]; void pushup(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];} void build(int l,in