题意:

有一个n个点,m条边的图,没有重边、自环,且每一条边最多属于一个环路。

给出q组询问,每次询问u,v两点间的路径有多少种可能。

思路:

先看下方样例说明:

由样例说明可以得知,路径上每经过一个环,路径种数就会乘2,而且最终答案一定是2^n;

因此使用tarjan算法求出图中的环,由于题目限制,求点双联通分量和边双联通分量效果相同。因边双联通分量好写,懒惰的作者采用了它 -~_~-

代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#define ll long long
#define MOD 1000000007
using namespace std;
vector<int>a[],b[];
stack<int>s;
int n,m,q,mm=,dep[],dfn[],low[],fa[],p[][],color[],times,cnt;
bool vis[],viss[];
void tarjan(int u){
int i,j,child=,v;
s.push(u);vis[u]=;
dfn[u]=low[u]=times++;
for(i=;i<a[u].size();i++){
v=a[u][i];
if(!vis[v]){
child++;fa[v]=u;
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(v!=fa[u]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
cnt++;
int count=,tmp;
while(!s.empty()){
tmp=s.top();
color[tmp]=cnt+n;
s.pop();count++;
if(tmp==u) break;
}
if(count==) color[tmp]=tmp;
}
}
void dfs(int u){
int i,v,t1,t2;t1=color[u];
viss[t1]=;vis[u]=;
for(i=;i<a[u].size();i++){
v=a[u][i];
t2=color[v];
if(viss[t2]) goto skip;
mm++;p[t2][]=t1;dep[t2]=dep[t1]+;
b[t1].push_back(t2);b[t2].push_back(t1);
skip:if(vis[v]) continue;
dfs(v);
}
return;
}
void init(){
int i,j;
for(j=;j<;j++){
for(i=;i<n+cnt;i++){
if(!b[i].size()) continue;
p[i][j]=p[p[i][j-]][j-];
}
}
}
void shrink(){
int i,j;
for(i=;i<=n;i++){
if(!dfn[i]) tarjan(i);
}
memset(vis,,sizeof(vis));memset(viss,,sizeof(viss));
dep[color[]]=;p[color[]][]=color[];dfs();
init();
return ;
}
ll calc(int k,int to){
if(k==to) return (to>n)?:;
else return calc(p[k][],to)*((k>n)?:);
}
ll lca(int l,int r){
int i,lca,tl=l,tr=r;
if(dep[l]<dep[r]) swap(l,r);
int diff=dep[l]-dep[r];
for(i=;i<;i++){
if(diff&(<<i)) l=p[l][i];
}
if(l==r) lca=l;
else{
for(i=;i>=;i--){
if(p[l][i]!=p[r][i]){
l=p[l][i];r=p[r][i];
}
}
lca=p[l][];
}
return calc(tl,lca)*calc(tr,lca)/((lca>n)?:);
}
int main(){
int i,t1,t2;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++) color[i]=i;
for(i=;i<=m;i++){
scanf("%d%d",&t1,&t2);
a[t1].push_back(t2);a[t2].push_back(t1);
}
shrink();
scanf("%d",&q);
for(i=;i<=q;i++){
scanf("%d%d",&t1,&t2);
printf("%lld\n",lca(color[t1],color[t2])%MOD);
}
}

最新文章

  1. myeclipse使用maven插件进行maven install时报错check $m2_home environment variable and mvn script match
  2. 【BZOJ 2440】【中山市选 2011】完全平方数 莫比乌斯函数+容斥原理
  3. StarWind的安装配置
  4. Android课程---帧布局 FrameLayout
  5. Linux workqueue疑问【转】
  6. 对已有的2个一维数组,譬如说A[],B[],经过最少循环找出2个数组重复的元素。
  7. 【测试】trunc和round的区别
  8. Appium下Android keyevent整理
  9. POJ2406----Power Strings解题报告
  10. 在C#中利用Nuget包使用SQLite数据库和Linq to SQLite
  11. 【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错
  12. Windows phone 之常用控件
  13. Pet--hdu4707
  14. 用SQL脚本移除视图中存在的机器名
  15. 射频识别技术漫谈(18)——Mifare Desfire
  16. Android操作HTTP实现和服务器通信
  17. hibernate 多对多关系总结
  18. Java集合系列[2]----LinkedList源码分析
  19. H5学习之旅-H5列表(8)
  20. PM过程能力成熟度4级

热门文章

  1. 转:比较spring cloud和dubbo,各自的优缺点是什么
  2. oracle下表空间、用户创建以及用户授权流程
  3. Redis 持久化操作
  4. 学习Pytbon第十八篇,异常处理
  5. python系列2之数据类型
  6. 虚拟机linux桥接联网问题
  7. Choosing Capital for Treeland CodeForces - 219D (树形DP)
  8. 关于修改zeppelin的代码显示
  9. 大话CNN经典模型:VGGNet
  10. 20145202马超 《Java程序设计》第五周学习总结