https://codeforces.com/contest/231/problem/E
看错题了。。。看成了要求每个点只经过一次的路径,然后想了一年。。。觉得这题比前面的2900分题难多了然后开始思考人生
要求每条路径只经过一次,那就很简单了
由于在仙人掌中每一个点最多属于一个环,那么在dfs树的过程中可以直接求出每个环的根节点(深度最小的)在哪,就相当于缩点了,还可以把缩点后的每个点的父亲节点是谁很方便的求出来
然后答案就是u,v的路径上所有的环的个数的2次幂了,包括u,v本身所在的环,这个用lca搞搞就好了,因为路径是边不重复,那么就不用考虑连接缩点以后图的边他原来的两个点是谁,如果是每个点只经过一次的路径就要考虑。。。现在还不会。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
const int mod=1e9+7;
int n,m,ans,cas,k,cnt,tot;
int a[maxl],b[maxl],cid[maxl],val[maxl];
int dy[maxl],dep[maxl],dis[maxl];
int f[19][maxl];
char s[maxl];
bool in[maxl],vis[maxl];
vector<int> e[maxl];
ll num[maxl];
inline void predfs(int u,int fa)
{
vis[u]=true;cid[u]=u;
for(int v:e[u])
{
if(v==fa) continue;
if(vis[v])
{
if(dep[v]<dep[u])
cid[u]=v,val[v]=1;
continue;
}
dep[v]=dep[u]+1;
predfs(v,u);
if(cid[v]!=v && cid[v]>0)
cid[u]=cid[v];
}
for(int v:e[u])
{
if(v==fa) continue;
if(cid[v]==v && dep[v]>dep[u])
f[0][v]=cid[u];
}
}
inline void dfs(int u)
{
vis[u]=true;
for(int v:e[u])
{
if(vis[v]) continue;
if(cid[v]==v)
{
dis[v]=dis[cid[u]]+val[v];
dep[v]=dep[cid[u]]+1;
}
dfs(v);
}
}
inline void prework()
{
scanf("%d%d",&n,&m);
num[0]=1;
for(int i=1;i<=n;i++)
num[i]=num[i-1]*2%mod;
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
predfs(1,0);
for(int i=1;i<=n;i++) vis[i]=false;
dfs(1);
}
inline int lca(int u,int v)
{
if(dep[u]<dep[v])
swap(u,v);
for(int i=18;i>=0;i--)
if(((dep[u]-dep[v])>>i)&1)
u=f[i][u];
if(u==v) return u;
for(int i=18;i>=0;i--)
if(f[i][u]!=f[i][v])
u=f[i][u],v=f[i][v];
return f[0][u];
}
inline void mainwork()
{
for(int i=1;i<=18;i++)
for(int j=1;j<=n;j++)
f[i][j]=f[i-1][f[i-1][j]];
scanf("%d",&k);int x,y,d,t;
for(int i=1;i<=k;i++)
{
scanf("%d%d",&x,&y);
d=lca(cid[x],cid[y]);
t=dis[cid[x]]+dis[cid[y]]-2*dis[d];
t+=val[d];
printf("%lld\n",num[t]);
}
}
inline void print()
{
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}