"蔚来杯"2022牛客暑期多校训练营3 F

"蔚来杯"2022牛客暑期多校训练营3 F

原题链接

题目大意

给定一个无向图,每次询问两点x,y,求是否存在一个n的排列,使得第一个元素为x,最后一个元素为y,且排列的任意一个前缀,任意一个后缀都联通。

分析

简单分析一下就可以知道,我们对原图缩点后,看缩完点后的图是或否是一条链。

在是一条链的前提下,我们询问的两个点两种情况合法。

  1. 缩完点之后只有一个联通块,即无割点。则一定合法。
  2. 缩完点后是一条大于等于两个联通块的链,则询问两点必须在链的两端,则我们只要看两点所待的v-dcc是不是一个点,若是则无解,不是的话,要看其度数是不是1,则可以判断出是否合法。

总的来说,模板题。

AC_code

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10,M = 4e5 + 10;
//要缩点建图的点与边都多开一倍保险
int h[N],e[M],ne[M],idx;
int dfn[N],low[N],ts;
int id[N],d[N];
int dcc_cnt;
bool cut[N];
stack<int> s;
vector<int> dcc[N];
int root,n,m;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void tarjan(int u)
{
    dfn[u] = low[u] = ++ts;
    s.push(u);
    if(u==root&&h[u]==-1)
    {
        dcc_cnt++;
        dcc[dcc_cnt].push_back(u);
        return ;
    }
    int cnt = 0;
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(!dfn[j])
        {
            tarjan(j);
            low[u] = min(low[u],low[j]);
            if(dfn[u]<=low[j])
            {
                cnt++;
                if(u!=root||cnt>1) cut[u] = 1;
                ++dcc_cnt;
                int y;
                do
                {
                    y = s.top();
                    s.pop();
                    dcc[dcc_cnt].push_back(y);
                }while(y!=j);
                dcc[dcc_cnt].push_back(u);
            }
        }else low[u] = min(low[u],dfn[j]);
    }
}

bool get()
{
    int num = dcc_cnt;
    for(int i=1;i<=n;i++)
        if(cut[i])
            id[i] = ++num;//给割点一个编号
    for(int i=1;i<=dcc_cnt;i++)
        for(auto x:dcc[i])
        {
            if(cut[x]) d[i]++,d[id[x]]++;
            else id[x] = i;
        }
    for(int i=1;i<=num;i++)
        if(d[i]>2)
            return 0;
    return 1;
}

int main()
{
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int u,v;scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    bool f = 1,ok = 0;
    for(int i=1;i<=n;i++)
        if(!dfn[i])
        {
            root = i;
            if(f)
            {
                tarjan(i);
                f = 0;
            }
            else
            {
                ok = 1;
                break;
            }
        }
    int q;scanf("%d",&q);
    if(n==2)
    {
        while(q--) cout<<"YES\n";
        return 0;
    }
    if(!ok&&!get()) ok = 1;
    while(q--)
    {
        int u,v;scanf("%d%d",&u,&v);
        u = id[u],v = id[v];
        if(ok) cout<<"NO\n";
        else if(!d[u]&&!d[v]) cout<<"YES\n";
        else if(d[u]==1&&d[v]==1&&u!=v) cout<<"YES\n";
        else cout<<"NO\n";
    }
    return 0;
}
posted @ 2022-08-07 19:13  艾特玖  阅读(17)  评论(0)    收藏  举报