求调,sub4WA前三个点
查看原帖
求调,sub4WA前三个点
1054181
longlinyu7楼主2024/9/11 15:42

Rt。

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int u,v,t,n,m,a[N];
struct node{
    int from,to,nextt;
}mp[N];
int h[N],cnt;
void add(int x,int y){
    mp[++cnt].to=y;
    mp[cnt].from=x;
    mp[cnt].nextt=h[x];
    h[x]=cnt;
}

vector<int>edge[N];
int vis[N],low[N],num[N],dfn;
int scc[N],tot,stac[N],top,flag[N];

int in[N];

int black_in, black_all;

void init(){
    memset(mp,0,sizeof(mp));
    memset(h,0,sizeof(h));
    memset(vis,0,sizeof(vis));
    memset(low,0,sizeof(low));
    memset(num,0,sizeof(num));
    memset(scc,0,sizeof(scc));
    memset(stac,0,sizeof(stac));
    memset(flag,0,sizeof(flag));
    memset(in,0,sizeof(in));
    memset(a,0,sizeof(a));
    for(int i=0;i<N;i++)edge[i].clear();
    dfn=tot=top=cnt=0;
    black_in=black_all=0;
}
void tarjan(int u){
    low[u]=num[u]=++dfn;
    stac[++top]=u;
    vis[u]=1;
    for(int i=h[u];i;i=mp[i].nextt){
        int v=mp[i].to;
        if(!num[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v]){
            low[u]=min(low[u],num[v]);
        }
    }
    if(low[u]==num[u]){
        scc[u]=++tot;
        vis[u]=0;
        flag[tot]=a[u];
        while(stac[top]!=u){
            int x=stac[top];
            scc[x]=tot;
            vis[x]=0;
            if(flag[tot]!=a[x]) flag[tot]= -1;
            top--;
        }
        top--;
    }
}

int topu(){  //!返回按照拓扑排序找到的第一个黑色点
    queue<int>q;
    while(!q.empty())q.pop();
    for(int i=1;i<=tot;i++){
        if(!in[i]){
            if(flag[i]==1) return i;
            q.push(i);
        }
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=0;i<edge[u].size();i++){
            int v=edge[u][i];
            if(flag[v]==1){
                return v;
            }
            in[v]--;
            if(!in[v])q.push(v);      
        }
    }
}
void dfs(int u){
    //! 沿着这条链走的必须全部为1;
    if(flag[u]==1)black_in++;
    else {
        black_in=-1;return;  // 经过了0就把着个设为-1,一定是不合法的
    }
    for(int i=0;i<edge[u].size();i++){
        int v=edge[u][i];
        dfs(v);
    }
    return ;
}

void read(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++){
        cin>>u>>v;
        add(u,v); 
    }
}
void work(){
    for(int i=1;i<=n;i++){  //先缩点
        if(!num[i]){
            tarjan(i);
        }
    }
    for(int i=1;i<=tot;i++){  //? 判断有没有奇形怪状的节点
        if(flag[i]==-1){
            cout<<"N";
            return;
        }
        if(flag[i]==1) black_all++;
    }
    if(black_all==0){ //! 如果全是白色点的话,后手必胜
        cout<<"B"; 
        return ;
    }
    for(int i=1;i<=cnt;i++){ // 建立新图
        int x=scc[mp[i].from],y=scc[mp[i].to];
        if(x!=y){
            edge[x].push_back(y);
            in[y]++;
        }
    }

    //! 两个独立的黑色节点, 后手必胜
    if(tot==2&&flag[1]==1&&flag[2]==1&&!edge[1].size()&&!edge[2].size()){
        cout<<"B";
        return ;
    }
    //! 只有两个节点,黑色 的点指向 白色 的点
    if(tot==2){
        if(edge[1].size()==1 &&flag[1]==1&&flag[2]==0){
            cout<<"B";
            return ;
        }
        if(edge[2].size()==1 &&flag[1]==0&&flag[2]==1){
            cout<<"B";
            return;
        }
    }

    dfs(topu());
    //! 输出A的条件
    //! 在拓扑排序找到第一个黑色点的时候,记录下来
    //! 然后从该点开始往后走,
    //! 必须满足 所经过的点都是1 ,且经过了所有的 1 
    if(black_in==black_all){
        cout<<"A";
    }  // 拓扑搜一遍
    else {
        cout<<"N";
    }
    return ;
}
signed main(){
    cin>>t;
    while(t--){
        init();
        read();
        work();
    }
    return 0;
}






2024/9/11 15:42
加载中...