[Codeforces 231E] Cactus (环缩点+LCA)

Codeforces - 231E

给定一个仙人掌图,问从 x点走到 y点有多少条路径
两条不同的路径必须每一条边都不相同


写了这个图论,相当于写了一个模拟
本来都是贴板的事,但是到仓库一看我并没有板
可能当初觉得很简单就没留板……
所以全程手写了,而且实际上我对图论并不是很熟
幸好不是在赛上,不然手速肯定被完爆

x到 y的路径,经过每个环的时候,就有两种走法
做法就是用边双联通分量对于每一个环缩成一个点,
每个大小大于 1的环权值为 2,否则就是 1
然后就变成了一棵树,预处理出根到每一点路径的前缀权值乘积
答案就是 x和y的前缀权值乘积,除两次lca(x,y)的前缀权值乘积,再乘一次 lca的权值

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <string>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define SQR(a) ((a)*(a))
#define PCUT puts("\n----------")
LL Pow(LL x, LL n, LL p)
{
    LL res=1;
    while(n)
    {
        if(n&1) res=res*x%p;
        x=x*x%p;
        n>>=1;
    }
    return res;
}
const int maxn=1e5+10;
const int MOD=1e9+7;
struct Graph
{
    int ndn, edn, last[maxn];
    int u[2*maxn], v[2*maxn], nxt[2*maxn];
    void init(int _n){ndn=_n; edn=0; MST(last,-1);}
    void adde(int _u, int _v)
    {
        u[edn]=_u; v[edn]=_v;
        nxt[edn]=last[_u];
        last[_u]=edn++;
    }
};
struct Tarjan
{
    Graph *G;
    int dfst, dfsn[maxn], lowv[maxn], iscut[2*maxn];
    int col[maxn], nc;
    LL pval[maxn], pvalr[maxn];
    int que[2*maxn], firp[maxn], idfsn[maxn], tail;
    int st[20][2*maxn];

    int solve(Graph*);
    int dfs(int,int);
    int color(int);
    int precom(int,int,LL);
    void st_init();
    int LCA(int,int);
};

int N,M;
Graph G;
Tarjan tar;

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
    #endif

    while(~scanf("%d%d", &N, &M))
    {
        G.init(N);
        for(int i=0,u,v; i<M; i++)
        {
            scanf("%d%d", &u, &v);
            G.adde(u,v); G.adde(v,u);
        }
        tar.solve(&G);
    }
    return 0;
}

int Tarjan::solve(Graph *g)
{
    G=g;
    dfst=0; CLR(dfsn); CLR(lowv); CLR(iscut);
    dfs(1,0);

    nc=0; CLR(col); CLR(pval);
    for(int i=1; i<=G->ndn; i++) if(!col[i]) {nc++; pval[nc]=color(i);}
    for(int i=1; i<=nc; i++) if(pval[i]>2) pval[i]=2;

    int tot=G->edn;
    G->init(nc);
    for(int e=0, u, v; e<tot; e++)
    {
        u = G->u[e], v = G->v[e];
        if(col[u]!=col[v]) G->adde(col[u], col[v]); 
    }


    dfst=0; tail=0; CLR(dfsn); CLR(firp);
    precom(1,0,1);
    st_init();

    int K;
    scanf("%d", &K);
    for(int i=0,x,y,l; i<K; i++)
    {
        scanf("%d%d", &x, &y);
        x=col[x], y=col[y];
        l=LCA(x,y);
        int ans = pvalr[x]*pvalr[y]%MOD * Pow(SQR(pvalr[l])%MOD, MOD-2, MOD)%MOD * pval[l]%MOD;
        printf("%d\n", ans);
    }

}

int Tarjan::dfs(int u, int f)
{
    lowv[u] = dfsn[u] = ++dfst;

    for(int e=G->last[u], v; ~e; e=G->nxt[e])
    {
        v=G->v[e];
        if(v==f) continue;
        if(!dfsn[v])
        {
            lowv[u] = min(lowv[u], dfs(v,u));
            if(lowv[v] > dfsn[u]) iscut[e] = iscut[e^1] = 1;
        }
        else lowv[u] = min(lowv[u], dfsn[v]);
    }
    return lowv[u];
}
int Tarjan::color(int u)
{
    int cnt=1;
    col[u] = nc;
    for(int e=G->last[u], v; ~e; e=G->nxt[e])
    {
        v=G->v[e];
        if(col[v] || iscut[e]) continue;
        cnt+=color(v);
    }
    return cnt;
}
int Tarjan::precom(int u,int f,LL prod)
{
    dfsn[u]=++dfst;
    idfsn[dfst] = u;
    pvalr[u] = pval[u]*prod%MOD;
    que[++tail] = dfsn[u];
    firp[u] = tail;
    for(int e=G->last[u],v; ~e; e=G->nxt[e]) if((v=G->v[e])!=f)
    {
        precom(v,u,pvalr[u]);
        que[++tail] = dfsn[u];
    }
}
void Tarjan::st_init()
{
    for(int i=1; i<=tail; i++) st[0][i] = que[i];
    for(int j=1, lim, len; j<=20; j++)
    {
        len=1<<j-1; lim=tail-(1<<j)+1;
        for(int i=1; i<lim; i++)
        {
            st[j][i] = min(st[j-1][i], st[j-1][i+len]);
        }
    }
}

int Tarjan::LCA(int x, int y)
{
    x=firp[x], y=firp[y];
    if(x>y) swap(x,y);
    int flr=log2(y-x+1), len=1<<flr;
    return idfsn[ min(st[flr][x], st[flr][y-len+1]) ];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值