bzoj2772: policija

题意

已知一个无向图,现在有若干个询问请你回答:
1.A B G1 G2求从A到B是否能不通过G1-G2这条已经存在的边
2.A B C求从A到B能否不通过C这个点

题解

其实很简单的一个题啊,想一想就想到了
但是我的“写法是不够优秀的”,于是去看了一下别人的写法,因此还是有收获的
明显的TJ然后分类讨论啊
本来就不连通的明显用并查集搞一搞就可以了
考虑割掉一个点的时候,被他分割出去的连通块,如果两个点在一个块里面,那么肯定是yes
否则如果如果一个在块里面,一个在块外面就是no
这么怎么弄呢?我一开始想的是弄dfs序,然后线段树上面子树修改
但这样会多一个log,其实我们只需要维护一个子树的并查集就可以了
然后块怎么弄呢?
我们可以对于打标记啊
标记的意思是说我们这个点会被割成一个块
而不是说某个点是不是割点
这个处理方法也很妙啊

时间复杂度O(n)
CODE:

#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int N=500005*2;
struct qq{int x,y,last;}e[N];
int num,last[N];
int n,m,q;
int F[N];//并查集 
void init (int x,int y)
{
    num++;
    e[num].x=x;e[num].y=y;
    e[num].last=last[x];
    last[x]=num;
}
vector<int> c1[N],c2[N];
int find (int x){return F[x]==x?F[x]:F[x]=find(F[x]);}
int dfn[N],low[N],id;
bool ans[N];
int A[N],B[N];
int fa[N];
void Dfs (int x,int ff)
{
    fa[x]=ff;
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==ff) continue;
        if (fa[y]!=-1) continue;
        Dfs(y,x);
    }
}
bool cut[N];//是否是被割出去的一个块 
bool check (int x,int xx,int yy)
{
    if (find(xx)==find(yy)) return true;
    if (dfn[xx]<dfn[x]&&dfn[yy]<dfn[x]) return true;
    return false;
}
void dfs (int x)
{
    low[x]=dfn[x]=++id;
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==fa[x]) continue;
        if (dfn[y]==0)
        {
            dfs(y);
            low[x]=min(low[x],low[y]);
            if (low[y]>=dfn[x]) cut[y]=true;
        }
        else low[x]=min(low[x],dfn[y]);
    }
    for (int u=0;u<c2[x].size();u++)
    {
        int id=c2[x][u];
        int xx=A[id],yy=B[id];
    //  printf("%d %d %d\n",x,xx,yy);
        if (xx==x||yy==x) {ans[id]=false;continue;}
        if (check(x,xx,yy)) continue ;
        if (dfn[xx]>dfn[x]&&cut[find(xx)]) ans[id]=false;
        if (dfn[yy]>dfn[x]&&cut[find(yy)]) ans[id]=false;
    }
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (dfn[y]>dfn[x])  F[find(y)]=find(x);
    }
    if (dfn[x]==low[x])
    {
        for (int u=0;u<c1[x].size();u++)
        {
            int id=c1[x][u];
            int xx=A[id],yy=B[id];
            if (check(x,xx,yy)) continue;
            ans[id]=false;
        }
    }
}
int main()
{
    memset(cut,false,sizeof(cut));
    id=0;memset(dfn,0,sizeof(dfn));
    num=0;memset(last,-1,sizeof(last));
    scanf("%d%d",&n,&m);
    for (int u=1;u<=n;u++) F[u]=u;
    for (int u=1;u<=m;u++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        init(x,y);init(y,x);
        int fx=find(x),fy=find(y);F[fx]=fy;
    }
    memset(fa,-1,sizeof(fa));
    for (int u=1;u<=n;u++)
        if (fa[u]==-1)
            Dfs(u,0);
    memset(ans,true,sizeof(ans));
    scanf("%d",&q);
    for (int u=1;u<=q;u++)
    {
        int op;
        scanf("%d%d%d",&op,&A[u],&B[u]);
        if (op==1)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if (find(A[u])!=find(B[u])) {ans[u]=false;continue;}
            if (fa[x]!=y) swap(x,y);
            if (fa[x]!=y) continue;
            c1[x].push_back(u);
        }
        if (op==2)
        {
            int x;
            scanf("%d",&x);
            if (find(A[u])!=find(B[u])) {ans[u]=false;continue;}
            c2[x].push_back(u);
        }
    }
    for (int u=1;u<=n;u++) F[u]=u;
    for (int u=1;u<=n;u++)
        if (fa[u]==0)
            dfs(u);
    for (int u=1;u<=q;u++)
    {
        if (ans[u]) printf("yes\n");
        else printf("no\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值