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

95 篇文章 1 订阅
77 篇文章 0 订阅

题目背景
XS中学化学竞赛组教练是一个酷爱炉石的人。
有一天他一边搓炉石一边监考,而你作为一个信息竞赛的大神也来凑热闹。
然而你的化竞基友却向你求助了。
“第1354题怎么做”<–手语 他问道。
题目描述
你翻到那一题:给定一个烃,只含有单键(给初中生的一个理解性解释:就是一堆碳用横线连起来,横线都是单条的)。
然后炎魔之王拉格纳罗斯用他的火焰净化了一切环(???)。所有的环状碳都变成了一个碳。如图所示。
这里写图片描述
然后指定多组碳,求出它们之间总共有多少碳。如图所示(和上图没有关系)。
这里写图片描述
但是因为在考试,所以你只能把这个答案用手语告诉你的基友。你决定用二进制来表示最后的答案。如图所示(不要在意,和题目没有什么没关系)。
这里写图片描述
输入输出格式
输入格式:
第一行两个整数n,m.表示有n个点,m根键
接下来m行每行两个整数u,v表示u号碳和v号碳有一根键
接下来一个整数tot表示询问次数
接下来tot行每行两个整数,a,b表示询问的两个碳的编号
输出格式:
共tot行
每行一个二进制数
输入输出样例
输入样例#1:
3 2
1 2
2 3
2
1 2
2 3
输出样例#1:
10
10
说明
1

//居然忘记发题解了,八月多A掉的一道题,到现在有人问我,才..
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 10010
#define MAXM 100010
int head[MAXN],dfn[MAXN],low[MAXN],visx,link[MAXN],tot,fa[MAXN][25];
int belong[MAXN],m,n,tot_,dep[MAXN],xx[MAXM],yy[MAXM];
bool exist[MAXN];
stack<int> st;
struct Edge{ int to,next; }e[MAXM*2],ee[MAXM*2];

inline int read(int &x){
    x=0;char c=getchar();
    while(c>'9'||c<'0') c=getchar();
    while(c>='0'&&c<='9'){ x=x*10+c-'0';c=getchar(); }
}

inline void Add_Edge(int u,int v){
    e[++tot].to=v;e[tot].next=head[u];head[u]=tot;
}
int cnt;
void Tarjan(int u,int from){
    low[u]=dfn[u]= ++visx; st.push(u); exist[u]=true;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v==from) continue;
        if(dfn[v]==-1) Tarjan(v,u),low[u]=min(low[u],low[v]);
        else if(exist[v]) low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        ++cnt;
        while(1){
            int v=st.top();st.pop();
            exist[v]=0; belong[v]=cnt;
            if(v==u) break;
        }
    }
}

inline void Add_Edge_(int u,int v){
    ee[++tot_].to=v;ee[tot_].next=link[u];link[u]=tot_;
}

void Make_New(){
    for(int i=1;i<=m;i++){
        if(belong[xx[i]]!=belong[yy[i]]){
            Add_Edge_(belong[xx[i]],belong[yy[i]]);
            Add_Edge_(belong[yy[i]],belong[xx[i]]);
        }
    }
}

void Get_Fa(){
    for(int j=1;j<=22;j++)
        for(int i=1;i<=cnt;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
}

void DFS(int u,int from,int deepth){
    dep[u]=deepth; fa[u][0]=from;
    for(int i=link[u];i;i=ee[i].next){
        int v=ee[i].to;
        if(v!=from) DFS(v,u,deepth+1);
    }
}

int LCA(int u,int v){
    if(dep[u]<dep[v]) swap(u,v);
    for(int j=0;j<=22;j++)
        if((dep[u]-dep[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 change(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(){
    read(n);read(m);
    memset(dfn,-1,sizeof dfn );
    memset(low,-1,sizeof low );
    for(int u,v,i=1;i<=m;i++){
        read(u),read(v);
        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);
    Make_New();
    DFS(belong[1],belong[1],0);
    Get_Fa();
    int T;
    read(T);
    while(T--){
        int u,v;
        scanf("%d%d",&u,&v);
        int ans=LCA(belong[u],belong[v]);
        change(dep[belong[u]]+dep[belong[v]]-dep[ans]-dep[ans]+1);
        //printf("%d\n",dep[belong[u]]+dep[belong[v]]-dep[ans]-dep[ans]+1);
    }
    return 0;
}
/*
6 5
1 2
2 3
3 4
1 5
5 6
1
4 6
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值