洛谷 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("\n");
 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 }

 

posted @ 2018-02-26 20:32  Frozen_Heart  阅读(316)  评论(0编辑  收藏  举报