cf1272E——bfs反边图

/*
分别对奇数点和偶数点各求一次,首先每个点连两条单向边
1.建立一个源点s,和所有偶数点连边,一次bfs出来的是所有奇数点的答案
2.建立一个源点t,和所有奇数点连边,一次bfs出来的是所有偶数点的答案 
*/
#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define N 400005

int n,a[N],dis[N],ans[N];
vector<int>G[N],G1[N],G2[N];
queue<int>q;

void add(int u,int v){G[u].push_back(v);}
void add1(int u,int v){G1[u].push_back(v);}
void add2(int u,int v){G2[u].push_back(v);}


int main(){
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        if(i-a[i]>0)add(i-a[i],i);
        if(i+a[i]<=n)add(i+a[i],i);
    }
    //求奇数点答案 
    for(int i=1;i<=n;i++)G1[i]=G[i];
    for(int i=1;i<=n;i++)
        if(a[i]%2==0)add1(n+1,i);
    memset(dis,0,sizeof dis);
    /*debug
    for(int i=1;i<=n;i++){
        for(auto x:G1[i])cout<<x<<" ";
        puts("");
    }*/
    
    q.push(n+1);
    while(q.size()){
        int now=q.front();q.pop();
        for(auto x:G1[now])if(!dis[x]){
            dis[x]=dis[now]+1;
            q.push(x);
        }
    }
    for(int i=1;i<=n;i++)
        if(a[i]%2)ans[i]=dis[i]-1;
    
    //求偶数点答案
    while(q.size())q.pop();
    for(int i=1;i<=n;i++) G2[i]=G[i];
    for(int i=1;i<=n;i++)
        if(a[i]%2)add2(n+1,i);
    memset(dis,0,sizeof dis);
    q.push(n+1);
    while(q.size()){
        int now=q.front();q.pop();
        for(auto x:G2[now])if(!dis[x]){
            dis[x]=dis[now]+1;
            q.push(x);
        }    
    }
    for(int i=1;i<=n;i++)
        if(a[i]%2==0)ans[i]=dis[i]-1;
        
    for(int i=1;i<=n;i++)
        cout<<ans[i]<<" ";
    puts("");
} 
原文地址:https://www.cnblogs.com/zsben991126/p/12114356.html