zoj4097 Rescue the Princess无向图缩点有重边+lca

题目链接:zoj4097 Rescue the Princess

题意:给一个有可能有重边的无向图,问从v,w到u是否有不相交的路径。

题解:先边双联通分量缩点就会的得到一片森林,如果不在同一颗树里面肯定,no,在同一颗树里面分情况讨论一下

#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define mk make_pair
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
#define pll pair<ll,ll>
typedef unsigned long long ull;
const int mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f;
const int N=1e5+5;
using namespace std;
int n,m,q;
vector<int>g[N],G[N];
int dfn[N],low[N],s[N],tot,cmp[N],scc_cnt,ind;
bool vis[N],ins[N];
int belong[N];
int block=0;
int tarjan(int v,int f,int b)
{
    low[v]=dfn[v]=++ind;
    s[++tot]=v;
    ins[v]=1;
    vis[v]=1;
    belong[v]=b;
    int flag=0;//判断是否为重边
    for(int to:g[v])
    {
        if(f==to)
        {
            if(++flag<2)continue;//大于等于二时有重边
        }
        if(!dfn[to])
        {
            tarjan(to,v,b);
            low[v]=min(low[v],low[to]);
        }
        else if(ins[v])low[v]=min(low[v],low[to]);
    }
    if(low[v]==dfn[v])
    {
        cmp[v]=++scc_cnt;
        while(s[tot]!=v)ins[s[tot]]=0,cmp[s[tot--]]=scc_cnt;
        ins[v]=0;
        tot--;
    }
}
int f[N][18],dep[N];
void dfs(int v,int fa,int d)
{
    vis[v]=1;
    f[v][0]=fa;
    dep[v]=d;
    for(int to:G[v])
    {
        if(to==fa)continue;
        dfs(to,v,d+1);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    int k=dep[x]-dep[y];
    for(int i=0;i<18;i++)
    {
        if((k>>i)&1)x=f[x][i];
    }
    if(x==y)return y;
    for(int i=17;i>=0;i--)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];y=f[y][i];
        }
    }
    return f[x][0];
}
void init()
{
    for(int i=0;i<=scc_cnt;i++)
    {
       G[i].clear(); dep[i]=0;
       for(int j=0;j<18;j++)f[i][j]=0;
    }
    for(int i=0;i<=n;i++)vis[i]=low[i]=dfn[i]=0,g[i].clear();
    scc_cnt=0;tot=0;ind=0;block=0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d %d %d",&n,&m,&q);
        for(int i=0;i<m;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            g[x].pb(y);
            g[y].pb(x);
        }
        for(int i=1;i<=n;i++)
        {
            if(!vis[i])
            {
                tarjan(i,0,++block);
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int to:g[i])
            {
                if(cmp[to]!=cmp[i])
                {
                    G[cmp[to]].pb(cmp[i]);
                }
            }
        }
        for(int i=1;i<=scc_cnt;i++)vis[i]=0;
        for(int i=1;i<=scc_cnt;i++)
        {
            if(!vis[i])
            {
                dfs(i,0,0);
            }
        }
        for(int i=1;i<18;i++)
        {
            for(int j=1;j<=scc_cnt;j++)
            {
                f[j][i]=f[f[j][i-1]][i-1];
            }
        }
        while(q--)
        {
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            if(belong[u]!=belong[v]||belong[v]!=belong[w]||belong[u]!=belong[w])
            {
                printf("No\n");continue;
            }
            u=cmp[u];v=cmp[v];w=cmp[w];
            bool f1=1;
            int uv=lca(u,v),uw=lca(u,w),vw=lca(v,w);
                if(uv==u)
                {
                    if(vw==u&&uw==u) ;
                    else if(uw!=u);
                    else f1=0;
                }
                else if(uv==v)
                {
                    if(uw==u);
                    else f1=0;
                }
                else
                {
                    if(uw!=u)f1=0;
                }
                if(f1)printf("Yes\n");
                else printf("No\n");
        }
    }
    return 0;
}
/*
1
2 1 2
1 2
1 1 1
2 1 2
*/

 

posted @ 2019-04-16 14:58  lhclqslove  阅读(297)  评论(0编辑  收藏  举报