压力

首先如果路径上有割点一定是必经点,然后如果是环上的点(除了割点)一定有多条路径可以到,所以环上(除了割点起点终点)都不必经。

所以点双缩点,重新建图(普通建图or圆方)

那么对于每组询问lca加普通树差标记一下,

对于每组询问拿数组zz记录起点终点,

最后dfs扫一遍

,结束时如果不为割点,直接输出zz

否则输出dfs扫出的ans

必经点模版题

#include<bits/stdc++.h>
#define ll long long
#define pt printf("******
")
#define A 1000000
using namespace std;
ll tot=0,head[A],sta[A],low[A],dfn[A],nxt[A],ver[A],deep[A],belong[A],cut[A];
ll tc=0,head_c[A],nxt_c[A],ver_c[A],sz[A],f[A][30],ans[A],zz[A];
ll n,m,q,t,num=0,cnt=0,root,top=0;
vector<ll> scc[A];
bool flag[A],vis[A];
void add(ll x,ll y){
    nxt[++tot]=head[x],head[x]=tot,ver[tot]=y;
}
void add_c(ll x,ll y){
    nxt_c[++tc]=head_c[x],head_c[x]=tc,ver_c[tc]=y;
}
void tarjan(ll x){
    low[x]=dfn[x]=++num;
    sta[++top]=x;ll vis=0;
    if(x==root&&!head[x])
    {
        cnt++;
        belong[x]=cnt;
        scc[cnt].push_back(x);
    }
    for(ll i=head[x];i;i=nxt[i]){
        ll y=ver[i];
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
            if(dfn[x]<=low[y]){
                vis++;
                if(x!=root||vis>1) cut[x]=1;
                cnt++;
                ll z;
                do{
                    z=sta[top--];
                    belong[z]=cnt;
                    scc[cnt].push_back(z);
                }while(z!=y);
                belong[x]=cnt;
                scc[cnt].push_back(x);
            }
        }
        else low[x]=min(low[x],dfn[y]);
    }
}
inline ll lca(ll x,ll y){
    if(deep[x]>deep[y]) swap(x,y);
    ll w;
    for(w=0;(1<<w)<=deep[y];w++);
    w--;
    for(ll i=w;i>=0;i--)
    {
//        printf("deep[%lld]=%lld deep[%lld]=%lld f[%lld]=%lld
",x,deep[x],y,deep[y],i,f[y][i]);
        
        if(deep[x]<=deep[f[y][i]]) y=f[y][i];
        if(deep[x]==deep[y]) break;
    }
    if(x==y) return x;
    for(ll i=w;i>=0;i--){
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    }
    return f[y][0];
}
void dfs2(ll x,ll de){
    deep[x]=de;flag[x]=1;
    for(ll i=head_c[x];i;i=nxt_c[i]){
        ll y=ver_c[i];
        if(flag[y])
            continue;
        f[y][0]=x;
        dfs2(y,de+1);
    }
}
ll dfs3(ll x){
    vis[x]=1;
    for(ll i=head_c[x];i;i=nxt_c[i]){
        ll y=ver_c[i];
        if(vis[y]) continue;
        ll to=dfs3(y);
        ans[x]+=to;
    }
    return ans[x];
}
int main(){
//    freopen("mkd.txt","r",stdin);
//    freopen("wa.txt","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&q);
    t=log(n)/log(2)+5;
    for(ll i=1;i<=m;i++){
        ll x,y;
        scanf("%lld%lld",&x,&y);
        add(x,y);add(y,x);
    }
    for(ll i=1;i<=n;i++){
        if(!dfn[i]) root=i,tarjan(i);
    }
    num=cnt;
    for(ll i=1;i<=n;i++)
    if(cut[i]) belong[i]=++num/*,printf("gd=%lld
",i)*/;
    for(ll i=1;i<=cnt;i++){
        ll size=scc[i].size();
        for(ll j=0;j<size;j++){
            if(cut[scc[i][j]]){
                add_c(i,belong[scc[i][j]]);
                add_c(belong[scc[i][j]],i);
            }
        }
    }
    dfs2(1,1),f[1][0]=1;
    for(ll j=1;j<=t;j++)
        for(ll i=1;i<=num;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    /*for(ll i=1;i<=n;i++){
        printf("belong=%lld
",belong[i]);    
    }
    for(ll i=1;i<=num;i++)
    {
        printf("deep[i]=%lld f[i][0]=%lld belong=%lld
",deep[belong[i]],f[belong[i]][0],belong[i]);
    }*/
    for(ll i=1;i<=q;i++){
        ll x,y;
        scanf("%lld%lld",&x,&y);
        ll lc=lca(belong[x],belong[y]);
//        cout<<lc<<endl;
        zz[x]++,zz[y]++;
//        printf("x=%lld y=%lld lc=%lld lf=%lld
",belong[x],belong[y],lc,f[lc][0]);
        ans[belong[x]]++;
        ans[belong[y]]++;
        ans[lc]--;
        if(f[lc][0]!=lc)ans[f[lc][0]]--;
    }
    dfs3(1);
    for(ll i=1;i<=n;i++){
        if(cut[i]) cout<<ans[belong[i]]<<endl;
        else cout<<zz[i]<<endl;
    }
    return 0;
}
View Code
我已没有下降的余地
原文地址:https://www.cnblogs.com/znsbc-13/p/11191540.html