CodeForces - 231E-Cactus(Tarjan缩点+LCA)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xbb224007/article/details/83692429

(一)题面:

题目链接:CodeForces - 231E - Cactus

A connected undirected graph is called a vertex cactus, if each vertex of this graph belongs to at most one simple cycle.

A simple cycle in a undirected graph is a sequence of distinct vertices v1, v2, ..., vt (t > 2), such that for any i (1 ≤ i < t) exists an edge between vertices vi and vi + 1, and also exists an edge between vertices v1 and vt.

A simple path in a undirected graph is a sequence of not necessarily distinct vertices v1, v2, ..., vt (t > 0), such that for any i (1 ≤ i < t)exists an edge between vertices vi and vi + 1 and furthermore each edge occurs no more than once. We'll say that a simple path v1, v2, ..., vt starts at vertex v1 and ends at vertex vt.

You've got a graph consisting of n vertices and m edges, that is a vertex cactus. Also, you've got a list of k pairs of interesting vertices xi, yi, for which you want to know the following information — the number of distinct simple paths that start at vertex xi and end at vertex yi. We will consider two simple paths distinct if the sets of edges of the paths are distinct.

For each pair of interesting vertices count the number of distinct simple paths between them. As this number can be rather large, you should calculate it modulo 1000000007 (109 + 7).

Input

The first line contains two space-separated integers n, m (2 ≤ n ≤ 105; 1 ≤ m ≤ 105) — the number of vertices and edges in the graph, correspondingly. Next m lines contain the description of the edges: the i-th line contains two space-separated integers ai, bi(1 ≤ ai, bi ≤ n) — the indexes of the vertices connected by the i-th edge.

The next line contains a single integer k (1 ≤ k ≤ 105) — the number of pairs of interesting vertices. Next k lines contain the list of pairs of interesting vertices: the i-th line contains two space-separated numbers xiyi (1 ≤ xi, yi ≤ nxi ≠ yi) — the indexes of interesting vertices in the i-th pair.

It is guaranteed that the given graph is a vertex cactus. It is guaranteed that the graph contains no loops or multiple edges. Consider the graph vertices are numbered from 1 to n.

Output

Print k lines: in the i-th line print a single integer — the number of distinct simple ways, starting at xi and ending at yi, modulo 1000000007 (109 + 7).

Examples

input

10 11
1 2
2 3
3 4
1 4
3 5
5 6
8 6
8 7
7 6
7 9
9 10
6
1 2
3 5
6 9
9 2
9 3
9 10

output

2
2
2
4
4
1

(二)题意:

定义一个简单环为:一个顶点数大于等于3的环。

给定一个n(n<=1e5)个顶点的无向图,满足:每一个顶点都最多属于一个简单环。

给出k(k<=1e5)组查询,每次查询给出(a,b),求无向图中从点a到点b的不同路径的数目(单条路径不能走重复的边)。

 

(三)题解:

由定义可知,这个图是由一些简单环之间连边组成的,且简单环之间不会共享点。

考虑从a->b的图中需要经过一个c个简单环,显然通过一个简单环的方法有两种路径(图一中的2->4),那么从a->b的简单路径数为2^c,也就是说我们只需要统计a->b的路径上需要通过多少个简单环(包括a和b所处的环),这个数目是一定的。

统计经过的环的个数。首先我们对所有的环缩点,那么由图的定义可知最终我们可以得到一颗树。标记树中每一个点是否是一个简单环(记录每一个新点包含的顶点数目)。接着查询(a->b)也就是查询(a'->b')(a',b'分别为缩完点以后的编号)的路径上需要经过的<被标记为简单环>的点的数目(包括a',b')。这就有点类似于LCA(最近公共祖先)求树上两点间的距离了。

我们以任何一个顶点为根节点,定义dist[i]为其子节点i到根节点的路径上需要经过简单环的数目(包括根节点和点i)。接着求a'和b'的LCA,设为f,则a'->b'需要经过的简单环的数目为:dist[a']+dist[b']-2*dist[f]+(f点为简单环?1:0)。需要加上f点是由于该点被减去了两次(如图二中的2,导致点2未被计算到路径内)。

这样整个流程就出来了:Tarjan缩点->建树->求dist[]数组->LCA求解。复杂度为线性的时间复杂度。

 

(四)代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<stack>
#include<vector>
#include<algorithm>
#define ll long long
#define mod 1000000007
using namespace std;
const int maxn=1e5+10;
stack<int>S;
vector<int>G[maxn],tree[maxn];
int n,m,q,dfs_clk,bcc_cnt,low[maxn],vis[maxn],p[maxn];
int dist[maxn],pre[maxn],fa[maxn],ans[maxn],tot[maxn];
int find(int x){return p[x]==x?x:p[x]=find(p[x]);}
ll ksm(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a%mod;
        b>>=1;a=a*a%mod;
    }
    return res;
}
void tarjan(int u,int f){
    pre[u]=low[u]=++dfs_clk;
    int sz=G[u].size();S.push(u);
    for(int i=0;i<sz;i++){
        int v=G[u][i];
        if(!pre[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(v!=f)low[u]=min(low[u],pre[v]);
    }
    if(pre[u]==low[u]){
        bcc_cnt++;
        while(1){
            int x=S.top();S.pop();
            fa[x]=bcc_cnt;
            tot[bcc_cnt]++;
            if(x==u)break;
        }
    }
}
void dfs(int u,int f,int d){
    dist[u]=d+(tot[u]>1);vis[u]=1;
    int sz=tree[u].size();
    for(int i=0;i<tree[u].size();i++){
        if(tree[u][i]!=f)dfs(tree[u][i],u,dist[u]);
    }
}
struct Query{
    int v,id;
    Query(int _v=0,int _id=0){
        v=_v;id=_id;
    }
};
vector<Query>Q[maxn];
void lca(int u,int f){
    int sz=tree[u].size();
    for(int i=0;i<sz;i++){
        int v=tree[u][i];
        if(v==f)continue;
        lca(v,u);vis[v]=1;
        p[find(v)]=find(u);
    }
    for(int i=0;i<Q[u].size();i++){
        int v=Q[u][i].v,id=Q[u][i].id;
        if(vis[v]){
            int d=dist[u]+dist[v]-2*dist[find(v)]+(tot[find(v)]>1);
            ans[id]=ksm(2,d);
        }
    }
}
int main(){
    #ifdef DanDan
    freopen("in.txt","r",stdin);
    #endif // DanDan
    int u,v;
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for(int i=1;i<=n;i++)
        if(!pre[i])tarjan(i,-1);
    for(u=1;u<=n;u++){
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(fa[u]!=fa[v])
                tree[fa[u]].push_back(fa[v]);
        }
    }
    for(int i=1;i<=bcc_cnt;i++){
        if(!vis[i])dfs(i,-1,0);p[i]=i;
    }memset(vis,0,sizeof vis);

    scanf("%d",&q);
    for(int i=0;i<q;i++){
        scanf("%d%d",&u,&v);
        if(fa[u]==fa[v]){ans[i]=2;continue;}
        Q[fa[u]].push_back(Query(fa[v],i));
        Q[fa[v]].push_back(Query(fa[u],i));
    }
    for(int i=1;i<=bcc_cnt;i++){
        if(!vis[i])lca(i,-1);
    }
    for(int i=0;i<q;i++){
        printf("%d\n",ans[i]);
    }
    return 0;
}

 

(五)总结:

①这个题总体思路还是比较清晰的,但是开始居然去纠结查询点是否是环的连接点的问题了,后来突然发现连接点也可以先绕自身一圈...。

②缩点的话由于这里的每一个环都是单个的简单环,可以花样写。

③写完以后突然发现我写快速幂干嘛,直接预处理不好吗(@_@;),强行加常数。

④LCA实际上是我前面一阵子才学的(离线),用到新知识来解题莫名地开心ヾ(≧▽≦*)o。

⑤本来是准备处理图非连通的情况的,但是写着写着最后忘了,不过数据好像保证了图连通。

猜你喜欢

转载自blog.csdn.net/xbb224007/article/details/83692429
今日推荐