[2-SAT] Codeforces875C.National Property

发现原来我并不会输出方案…

这题只要找第一个不相同的位置 pos

如果 ai,pos>ai+1,pos 那么 ai,pos 一定是大写, ai+1,pos 一定是小写

如果 ai,pos<ai+1,pos 那么如果 ai,pos 是大写, ai+1,pos 也要大写, ai+1,pos 是小写,那么 ai,pos 也要是小写

就这样建边跑2-SAT就好了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <queue>
#include <assert.h>
#include <cstring>

using namespace std;

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void rea(int &x){
    char c=nc(); x=0;
    for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

const int N=500010,P=1e9+7;

int n,m,cnt;
int a[N],b[N],G[N],bg[N],sm[N];
struct edge{
    int t,nx;
}E[N*20];

inline void addedge(int x,int y){
    E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
    //cout<<x<<' '<<y<<endl;
}

int bel[N],stk[N],vis[N],low[N],dfn[N],top,tms,g;

void tarjan(int x){
  vis[x]=1;
  dfn[x]=low[x]=++tms;
  stk[++top]=x;
  for(int i=G[x];i;i=E[i].nx){
    if(!vis[E[i].t]) tarjan(E[i].t);
    if(vis[E[i].t]==1) low[x]=min(low[x],low[E[i].t]);
  }
  if(low[x]==dfn[x]){
    ++g; int k;
    do{
      k=stk[top--];
      bel[k]=g;
      vis[k]=2;
    }while(top && k!=x);
  }
}

int Q[N],l,r;

int main(){
    scanf("%d%d",&n,&m);
    scanf("%d",a); 
    for(int i=1;i<=*a;i++) scanf("%d",&a[i]);
    scanf("%d",b);
    for(int i=1;i<=*b;i++) scanf("%d",&b[i]);
    int cur;
    for(cur=1;cur<=*a && cur<=*b;cur++) if(a[cur]!=b[cur]) break;
    if(cur<=*a && cur<=*b){
        if(a[cur]>b[cur]) addedge(a[cur]<<1,a[cur]<<1|1),addedge(b[cur]<<1|1,b[cur]<<1),bg[a[cur]]=1,sm[b[cur]]=1;
        else addedge(b[cur]<<1|1,a[cur]<<1|1),addedge(a[cur]<<1,b[cur]<<1);
    }
    if(*a!=*b && cur>*b) return puts("No"),0;
    int *A=b,*B=a;
    for(int i=1;i<n-1;i++){
        scanf("%d",B);
        for(int j=1;j<=*B;j++) scanf("%d",&B[j]);
        int cur;
        for(cur=1;cur<=*A && cur<=*B;cur++)
            if(A[cur]!=B[cur]) break;
        if(cur<=*A && cur<=*B){
            if(A[cur]>B[cur]) addedge(A[cur]<<1,A[cur]<<1|1),addedge(B[cur]<<1|1,B[cur]<<1),bg[A[cur]]=1,sm[B[cur]]=1;
            else addedge(B[cur]<<1|1,A[cur]<<1|1),addedge(A[cur]<<1,B[cur]<<1);
        } 
        if(*A!=*B && cur>*B) return puts("No"),0;
        swap(A,B);
    }
    for(int i=2;i<=(m<<1|1);i++)
        if(!vis[i]) tarjan(i);
    for(int i=1;i<=m;i++)
        if(bel[i<<1]==bel[i<<1|1]) return puts("No"),0;
    puts("Yes");

  vector<int> ans;
    for(int i=1;i<=m;i++){
        if(bel[i<<1|1]<bel[i<<1]) ans.push_back(i);
    }
    printf("%d\n",ans.size());
    for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值