1. 程式人生 > 實用技巧 >ZJU-ICPC Summer 2020 Contest 7 D Cafeterias

ZJU-ICPC Summer 2020 Contest 7 D Cafeterias

https://zjusummer.contest.codeforces.com/group/clkkguw3vK/contest/102661/problem/D

對於一個節點,設有食物時為黑色,無食物時為白色,可以發現,一個節點頂多經歷三個階段

\(1.\)一直是白色

\(2.\)黑白閃爍

\(3.\)一直是黑色

這樣比較難處理,我們對於奇偶分別討論

一個狀態記錄為\((v,eo)\)\(v\)表示其節點標號,\(eo\)表示其奇偶性,那麼對於一個狀態,只有前面全白,後面全黑的過渡過程

我們記錄每個狀態第一次黑色的位置,可以通過最短路獲得,直接\(BFS\)

轉移:\((u,eo)->(v,eo \quad xor\quad 1)\)

對於詢問,直接二分即可

\(C++ Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#define N 4000005
using namespace std;
int n,m,k,x,y,t,T;
int tot,head[N],nxt[N],d[N],rd[N];
int c[N],g[2][N],g0[N],g1[N];
bool s[N];
struct node
{
    int dis,eo,id;
};
queue<node>q;
void add(int x,int y)
{
    tot++;
    d[tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
    rd[y]++;
}
void Solve()
{
    for (int i=1;i<=n;i++)
        g[0][i]=-1,g[1][i]=-1;
    for (int i=1;i<=k;i++)
        if (s[c[i]])
            q.push((node){1,1,c[i]}),g[1][c[i]]=0;
    while (!q.empty())
    {
        node u=q.front();
        q.pop();
        for (int i=head[u.id];i;i=nxt[i])
        {
            int v=d[i];
            if (g[u.eo^1][v]!=-1)
                continue;
            q.push((node){u.dis+1,u.eo^1,v});
            g[u.eo^1][v]=u.dis+1;
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=k;i++)
    {
        scanf("%d",&c[i]);
        s[c[i]]=true;
    }
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for (int i=1;i<=n;i++)
        if (!rd[i])
            s[i]=false;
    Solve();
    for (int i=1;i<=n;i++)
        g0[i]=g[0][i],g1[i]=g[1][i];
    sort(g0+1,g0+n+1);
    int g_0=0;
    for (int i=1;i<=n;i++)
        if (g0[i]==-1)
            g_0++;
    sort(g1+1,g1+n+1);
    int g_1=0;
    for (int i=1;i<=n;i++)
        if (g1[i]==-1)
            g_1++;
    scanf("%d",&T);
    while (T --> 0)
    {
        scanf("%d",&t);
        if (t==1)
            printf("%d\n",k); else
            {
                int o;
                if (t&1)
                    o=upper_bound(g1+1,g1+n+1,t)-g1-1; else
                    o=upper_bound(g0+1,g0+n+1,t)-g0-1;
                o=min(o,n);
                o-=(t&1)?g_1:g_0;
                printf("%d\n",o);
            }
    }
}