zoukankan      html  css  js  c++  java
  • 洛谷 P2783 有机化学之神偶尔会做作弊(Tarjan,LCA)

    题目背景

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

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

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

    “第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<n<=10000,1<m<=50000

    (两个碳不成环)

    这是一道包含了两个板子的题目:tarjan+lca。(应该还是比较明显的)

    但是这里我们发现C与C之间必须要连一条双向边,不符合普通tarjan的要求。

    我们注意到题目中的条件:两个C不成环。那我们只要让当前的点不递归到它的"爸爸"就可以了。

    lca是在树上求两点距离的很常见,常用的办法,在碰到树上题目是可以多考虑。

    至于2进制我打的不是很简洁,可以学习一下别人的。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 int n,m,cnt,vistime,sum,top;
      4 int head[10010],h[10010],dfn[10010],low[10010],s[10010],num[10010],deep[10010],f[10010][23],belong[10010],ans[10010];
      5 bool instack[10010];
      6 struct node{
      7 int to,next;
      8 }edge[100010],e[100010];
      9 int read()
     10 {
     11     int x=0,w=1;char ch=getchar();
     12     while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
     13     while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
     14     return x*w;
     15 }
     16 void add(int x,int y)
     17 {
     18     cnt++;
     19     edge[cnt].to=y;
     20     edge[cnt].next=head[x];
     21     head[x]=cnt;
     22 }
     23 void ad(int x,int y)
     24 {
     25     cnt++;
     26     e[cnt].to=y;
     27     e[cnt].next=h[x];
     28     h[x]=cnt;
     29 }
     30 void print(int x)
     31 {
     32     int cnt=0;
     33     if(x==0) {printf("0");return;}
     34     if(x<0) printf("-"),x=-x;
     35     while(x)
     36     {
     37         cnt++;
     38         if(x&1) ans[cnt]=1;
     39         x>>=1;
     40     }
     41     for(int i=cnt;i>0;i--)
     42     {
     43         printf("%d",ans[i]);
     44         ans[i]=0;
     45     }
     46     printf("
    ");
     47 }
     48 void tarjan(int,int);
     49 void build(int,int,int);
     50 int lca(int,int);
     51 int main()
     52 {
     53     int u,v,tot;
     54     n=read();m=read();
     55     for(int i=1;i<=m;i++)
     56     {
     57         u=read();v=read();
     58         add(u,v);
     59         add(v,u);
     60     }
     61     cnt=0;
     62     for(int i=1;i<=n;i++)
     63     {
     64         if(!dfn[i])
     65         tarjan(i,0);
     66     }
     67     for(int i=1;i<=n;i++)
     68     {
     69         for(int j=head[i];j;j=edge[j].next)
     70         {
     71             v=edge[j].to;
     72             if(belong[v]!=belong[i])
     73             {
     74                 ad(belong[i],belong[v]);
     75             }
     76         }
     77     }
     78     build(1,0,1);
     79     for(int j=1;j<=20;j++)
     80     for(int i=1;i<=sum;i++)
     81     {
     82         f[i][j]=f[f[i][j-1]][j-1];
     83     }
     84     tot=read();
     85     for(int i=1;i<=tot;i++)
     86     {
     87         u=read();v=read();
     88         int LCA=lca(belong[u],belong[v]);
     89         print(deep[belong[u]]+deep[belong[v]]-2*deep[LCA]+1);
     90     }
     91 }
     92 void tarjan(int u,int from)//增加参数,防止搜回去
     93 {
     94     int v;
     95     dfn[u]=low[u]=++vistime;
     96     s[++top]=u;
     97     instack[u]=true;
     98     for(int i=head[u];i;i=edge[i].next)
     99     {
    100         v=edge[i].to;
    101         if(v==from) continue;
    102         if(!dfn[v])
    103         {
    104             tarjan(v,u);
    105             low[u]=min(low[v],low[u]);
    106         }
    107         else if(instack[v])
    108         {
    109             low[u]=min(low[u],dfn[v]);
    110         }
    111     }
    112     if(dfn[u]==low[u])
    113     {
    114         sum++;
    115         do
    116         {
    117             v=s[top--];
    118             belong[v]=sum;
    119             num[sum]++;
    120             instack[v]=false;
    121         }while(u!=v);
    122     }
    123 }
    124 void build(int k,int fa,int d)
    125 {
    126     int v;
    127     deep[k]=d;
    128     for(int i=h[k];i;i=e[i].next)
    129     {
    130         v=e[i].to;
    131         if(v!=fa&&!deep[v])
    132         {
    133             f[v][0]=k;
    134             build(v,k,d+1);
    135         }
    136     }
    137 }
    138 int lca(int x,int y)
    139 {
    140     if(deep[x]>deep[y]) swap(x,y);
    141     for(int i=20;i>=0;i--)
    142     if(deep[f[y][i]]>=deep[x]) y=f[y][i];
    143     if(x==y) return x;
    144     for(int i=20;i>=0;i--)
    145     {
    146         if(f[x][i]!=f[y][i])
    147         x=f[x][i],y=f[y][i];
    148     }
    149     return f[x][0];
    150 }
  • 相关阅读:
    LinuxDay10——文本处理工具sed
    设计模式原则----开放封闭原则
    模式设计原则----单一职责原则
    策略模式
    建模工具
    vs查看源码行数
    单例模式(Singleton Pattern)
    UML
    简单工厂模式(Simple Factory Pattern)
    winform ProgressBar
  • 原文地址:https://www.cnblogs.com/lsgjcya/p/8475925.html
Copyright © 2011-2022 走看看