Fat Brother And His Love
Time Limit: 2 Sec Memory Limit: 128 MBDescription
Aswe know, fat Brother and his goddess is in a same city. The city isconsist of N locations and the N locations is connected by M roads.Fat Brother has a crush on his goddess, but when he knew that thegoddess want to date with other boy, he is reluctant. So he decidedto stop their dating, then he go to find a single giant bomb from thewarehouse. He can use this giant bomb blew up a road. Fat Brotherwondered whether he can separate goddess and other boy by blowing upa road. Fat Brother gives Q questions that each query is given twonumbers u and v which means the number of the location of the goddessand the boy. If fat Brother can separate goddess and other boy,output a line “Hei!Hei!Hei!” and a line integer denoting the waysto separate them. If fat Brother can't, output a line “No! Ichoose to go die!”.
Youcan think the city which Fat Brother, goddess and boys are in is anundirected graph, and the graph is always connected in the beginning.
Ifyou can't understand it, you should observate the sample Input andsample Output
Input
There are multiple test cases. The first line of input contains an integer T (T <= 25) indicating the number of test cases. For each test case:
The first line contains three integer N, M and Q denoting there are N locations and M roads in the city. The Q denoting there are Q questions. (1 <= N <= 100000, 1 <= m <= 100000, 1 <= Q <= 100000)
Each of the 2…M + 1 lines contains two integers u and v denoting there is a undirected road between u and v.
Each of the M + 2 … M + 1 + Q lines contains two integer u and v denoting the fat Brother's question.
Output
For each case, output acconding to Title Description.
Sample Input
2
9 11 19
1 2
1 3
2 3
2 4
4 5
4 6
5 6
6 7
7 8
7 9
8 9
1 2
1 3
2 3
2 4
4 5
4 6
5 6
6 7
7 8
7 9
8 9
1 4
4 7
8 5
3 6
9 4
1 6
7 3
2 9
10 9 8
1 2
1 3
3 4
4 5
3 6
6 7
3 8
8 9
8 10
1 5
1 2
7 5
9 4
2 3
6 2
4 1
3 9
Sample Output
No! I choose to go die!
No! I choose to go die!
No! I choose to go die!
Hei!Hei!Hei!
1
No! I choose to go die!
No! I choose to go die!
No! I choose to go die!
Hei!Hei!Hei!
1
No! I choose to go die!
No! I choose to go die!
No! I choose to go die!
Hei!Hei!Hei!
1
Hei!Hei!Hei!
1
Hei!Hei!Hei!
1
Hei!Hei!Hei!
1
Hei!Hei!Hei!
1
Hei!Hei!Hei!
1
Hei!Hei!Hei!
2
Hei!Hei!Hei!
2
Hei!Hei!Hei!
3
Hei!Hei!Hei!
1
Hei!Hei!Hei!
4
Hei!Hei!Hei!
3
Hei!Hei!Hei!
2
Hei!Hei!Hei!
3
Hei!Hei!Hei!
2
Hei!Hei!Hei!
2
题意:给定n个点、m条边的无向连通图,有q个询问,问有多少条边是从点u到点v必经的。有解输出“Hei!Hei!Hei!”和边数,无解输出“No! I choose to go die!”。
题解:先tarjan缩点建图
然后做一遍lca
那么两点同一个联通分量里面肯定是go die!
否则我们找到两个点的lca
然后求一下深度即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int head[100005],cnt,tot,inde,top,tots,dfn[200005],low[200005],ef[200005],bccnum,bcc[200005],st[200005],heads[100005],dp[100005];
struct node{
int fro,to,nex,yes;
}edge[200005],edges[200005];
const int MAXN = 100010;
int rmq[2*MAXN];//rmq数组,就是欧拉序列对应的深度序列
struct ST
{
int mm[2*MAXN];
int dp[2*MAXN][20];//最小值对应的下标
void init(int n)
{
mm[0] = -1;
for(int i = 1;i <= n;i++)
{
mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
dp[i][0] = i;
}
for(int j = 1; j <= mm[n];j++)
for(int i = 1; i + (1<<j) - 1 <= n; i++)
dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
}
int query(int a,int b)//查询[a,b]之间最小值的下标
{
if(a > b)swap(a,b);
int k = mm[b-a+1];
return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
}
}sts;
int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
int P[MAXN];//P[i]表示点i在F中第一次出现的位置
void add(int u,int v){
edge[tot].fro=u;
edge[tot].to=v;
edge[tot].nex=head[u];
edge[tot].yes=0;
head[u]=tot++;
}
void dfs(int u,int pre,int dep)
{
dp[u]=dep;
F[++cnt] = u;
rmq[cnt] = dep;
P[u] = cnt;
for(int i = heads[u];i != -1;i = edges[i].nex)
{
int v = edges[i].to;
if(v == pre)continue;
dfs(v,u,dep+1);
F[++cnt] = u;
rmq[cnt] = dep;
}
}
void LCA_init(int root,int nodenum)//查询LCA前的初始化
{
cnt = 0;
dfs(root,root,0);
sts.init(2*nodenum-1);
}
int query_lca(int u,int v)//查询u,v的lca编号
{
return F[sts.query(P[u],P[v])];
}
void adds(int u,int v){
edges[tots].fro=u;
edges[tots].to=v;
edges[tots].nex=heads[u];
edges[tots].yes=0;
heads[u]=tots++;
}
void tarjan(int root){//求强连通分量
dfn[root]=low[root]=++inde;
st[++top]=root;
for(int i=head[root];~i;i=edge[i].nex){
int v=edge[i].to;
if(ef[i])continue;
ef[i]=ef[i^1]=1;
if(!dfn[v]){
tarjan(v);
low[root]=min(low[root],low[v]);
if(dfn[root]<low[v]){
edge[i].yes=edge[i^1].yes=1;
}
}
else low[root]=min(low[root],dfn[v]);
}
if(low[root]==dfn[root]){
bccnum++;
for(;;){
int x=st[top--];
bcc[x]=bccnum;
if(x==root)break;
}
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int x,y,n,m,q,i,j;
tot=0;
bccnum=0;
top=0;
inde=0;
tots=0;
memset(head,-1,sizeof(head));
memset(heads,-1,sizeof(heads));
memset(dfn,0,sizeof(dfn));
memset(bcc,0,sizeof(bcc));
memset(low,0,sizeof(low));
memset(ef,0,sizeof(ef));
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
tarjan(1);
for(i=0;i<tot;i+=2){
if(edge[i].yes){
adds(bcc[edge[i].fro],bcc[edge[i].to]);
adds(bcc[edge[i].to],bcc[edge[i].fro]);
}
}
LCA_init(1,bccnum);
while(q--){
int x,y;
scanf("%d%d",&x,&y);
if(bcc[x]==bcc[y]){
printf("No! I choose to go die!\n");
}
else{
int zu=query_lca(bcc[x],bcc[y]);
printf("Hei!Hei!Hei!\n%d\n",dp[bcc[x]]+dp[bcc[y]]-2*dp[zu]);
}
}
}
return 0;
}