• Cactus CodeForces


    大意: 给定无向图, 每个点最多属于一个简单环, 多组询问, 求给定起点终点, 有多少条简单路径.

    先缩环, 然后假设两点树上路径经过$cnt$个环, 那么答案就为$2^{cnt}$.

    要注意缩环建树时要加单向边.

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define pb push_back
    using namespace std;
    
    template <class T> void rd(T &x){x=0;bool f=0;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}if(f)x=-x;}
    
    const int N = 1e6+10, P = 1e9+7;
    int n,m,dep[N],fa[N];
    int s[N],vis[N],sz[N];
    int son[N],top[N],v[N],fac[N];
    vector<int> g[N],gg[N];
    int Find(int x) {return s[x]?s[x]=Find(s[x]):x;}
    void add(int x, int y) {
    	x=Find(x),y=Find(y);
    	if (x!=y) s[x]=y;
    }
    void get(int x, int y) {
        if (dep[x]<dep[y]) return;
    	vis[y] = 1;
        for (; x!=y; x=fa[x]) add(x,y),vis[x]=1;
    }
    void dfs(int x, int f) {
        fa[x]=f,dep[x]=dep[f]+1;
        for (int y:g[x]) if (y!=f) {
            if (dep[y]) get(x,y);
            else dfs(y,x);
        }
    }
    void dfs2(int x, int f, int d) {
    	sz[x]=1,fa[x]=f,dep[x]=d,v[x]=v[f]+vis[x];
    	for (int y:gg[x]) if (y!=f) {
    		dfs2(y,x,d+1),sz[x]+=sz[y];
    		if (sz[y]>sz[son[x]]) son[x]=y;
    	}
    }
    void dfs3(int x, int tf) {
    	top[x] = tf;
    	if (son[x]) dfs3(son[x],tf);
    	for (int y:gg[x]) if (!top[y]) dfs3(y,y);
    }
    int lca(int x, int y) {
    	while (top[x]!=top[y]) {
    		if (dep[top[x]]<dep[top[y]]) swap(x,y);
    		x = fa[top[x]];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    
    int main() {
    	fac[0]=1;
    	REP(i,1,N-1) fac[i]=fac[i-1]*2%P;
    	rd(n),rd(m);
    	REP(i,1,m) {
    		int u, v;
    		rd(u),rd(v);
    		if (u==v) continue;
    		g[u].pb(v),g[v].pb(u);
    	}
    	dfs(1,0);
    	int rt = 1;
    	REP(i,1,n) if (vis[i]) rt = Find(i);
    	REP(i,1,n) {
    		for (int j:g[i]) {
    			int u=Find(i),v=Find(j);
    			if (u!=v) gg[u].pb(v);
    		}
    	}
    	dfs2(rt,0,0),dfs3(rt,rt);
    	scanf("%d", &m);
    	while (m--) {
    		int x, y;
    		scanf("%d%d", &x, &y);
    		x = Find(x), y = Find(y);
    		int l = lca(x,y);
    		printf("%d
    ", fac[v[x]+v[y]-v[l]-v[fa[l]]]);
    	}
    }
    
  • 相关阅读:
    053-98
    053-672
    053-675
    1031 Hello World for U (20分)
    1065 A+B and C (64bit) (20分)
    1012 The Best Rank (25分)
    1015 Reversible Primes (20分)
    1013 Battle Over Cities (25分)
    1011 World Cup Betting (20分)
    1004 Counting Leaves (30分)
  • 原文地址:https://www.cnblogs.com/uid001/p/11046891.html
Copyright © 2020-2023  润新知