【tarjan缩点+LCA】ZOJ - 4097 - Rescue the Princess

题目链接<http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5986>


题意:

给出一张图,两个起点和一个终点,问是否存在两条不相交的路。


题解:

先来个并查集,判断是否在一个连通块内。

再缩个点,如果都在一个点内,那么一定可以。

否则就是棵树,lca分类讨论一下。

赛上居然数组开小,疯狂自闭..


#include<iostream>
#include<cstdio>
#include<string.h>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
const int M=2e5+7;
const int N=1e5+7;
int t,n,m,q;
struct Edge{
    int v,nxt;
    Edge(int v=0,int nxt=0):v(v),nxt(nxt){}
}edge[M*2],e[M*2];

int p[N],edn;
void add(int u,int v){
    edge[++edn]=Edge(v,p[u]);p[u]=edn;
    edge[++edn]=Edge(u,p[v]);p[v]=edn;
}

int dfn[N],low[N],bcc[N],bccnum,ind,st[N],top;
bool ef[M*2];
void tarjan(int u){
    dfn[u]=low[u]=++ind;
    st[++top]=u;
    for(int i=p[u];~i;i=edge[i].nxt){
        int v=edge[i].v;
        if(ef[i]) continue;
        ef[i]=ef[i^1]=1;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
            /*if(dfn[u]<low[v]){
                ef[i]=ef[i^1]=2;
            }*/
        }
        else low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        bccnum++;
        while(1){
            int x=st[top--];
            bcc[x]=bccnum;
            if(x==u) break;
        }
    }
}

int hd[M],ed;
void ad(int u,int v){
    e[++ed]=Edge(v,hd[u]);hd[u]=ed;
}

void rebuild(){
    memset(hd,-1,sizeof(hd));ed=-1;
    for(int x=1;x<=n;x++){
        int u=bcc[x];
        for(int i=p[x];~i;i=edge[i].nxt){
            int v=bcc[edge[i].v];
            if(u==v) continue;
            ad(u,v);
        }
    }
}

void init(){
    memset(bcc,0,sizeof(bcc));bccnum=0;
    memset(p,-1,sizeof(p));edn=-1;
    memset(dfn,0,sizeof(dfn));
    memset(ef,false,sizeof(ef));
    top=ind=0;
}


int fa[N][20],d[N],dis[N];
void dfs(int u){
    for(int i=hd[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if(v==fa[u][0])continue;
        d[v]=d[u]+1;
        fa[v][0]=u;
        dfs(v);
    }
}
void initlca(){
    for(int j=1;(1<<j)<=bccnum;j++){
        for(int i=1;i<=bccnum;i++){
            fa[i][j]=fa[fa[i][j-1]][j-1];
        }
    }
}
int lca(int a,int b){
    if(d[a]>d[b])swap(a,b);
    int f=d[b]-d[a];
    for(int i=0;(1<<i)<=f;i++){
        if((1<<i)&f) b=fa[b][i];
    }
    if(a!=b){
        for(int i=(int)log2(N);i>=0;i--){
            if(fa[a][i]!=fa[b][i]){
                a=fa[a][i]; b=fa[b][i];
            }
        }
        a=fa[a][0];
    }
    return a;
}

int ff[N];
int fd(int x){return x==ff[x]?x:ff[x]=fd(ff[x]);}

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=n;i++) ff[i]=i;
        init();
        int u,v;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            if(u==v) continue;
            add(u,v);
            int fu=fd(u),fv=fd(v);
            ff[fu]=fv;
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            if(!bcc[i]) tarjan(i);
        }
        rebuild();
        memset(d,0,sizeof(d));
        for(int i=1;i<=bccnum;i++){
            if(!d[i]) dfs(i);
        }
        initlca();
        int x,y,z;
        while(q--){
            scanf("%d%d%d",&x,&y,&z);
            if(fd(x)!=fd(y)||fd(x)!=fd(z)){
                printf("No\n");
                continue;
            }
            x=bcc[x];y=bcc[y];z=bcc[z];
            int pp=lca(y,z);
            if((lca(pp,x)==pp||pp==x)&&(lca(x,y)==x||lca(x,z)==x)){
                printf("Yes\n");
            }
            else printf("No\n");
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值