bzoj3495 PA2010 Riddle(2-sat+建图优化)

版权声明:转载附上原文地址即可~欢迎各位神犇来虐~ https://blog.csdn.net/Icefox_zhx/article/details/79954283

我们把每个点当不当首部作为两种选择,得到了一个很显然的2-sat。

但是对于m个点中有且仅有一个点当首都这个条件我们的建边是O(n^2)的,gg

我们考虑如何优化这个建图,如果我们选择第i个点作为首都,则1~i-1都不能当首都,i+1~m也都不能。于是我们想到前缀和后缀和优化,新建2m个点,分别表示1~i有没有首都,i~n有没有首都。

然后我们把这些点之间的限制关系建出来,边数就是O(n)的。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
#define inf 0x3f3f3f3f
#define N 3000010
#define M 12000010
#define ll long long
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,tot=0,m,h[N<<1],num=0,dfn[N<<1],low[N<<1],dfnum=0,bel[N<<1],scc=0;
bool inq[N<<1];stack<int>qq;
struct edge{
    int to,next;
}data[M];
inline void add(int x,int y){
    data[++num].to=y;data[num].next=h[x];h[x]=num;
}
inline void tarjan(int x){
    dfn[x]=low[x]=++dfnum;qq.push(x);inq[x]=1;
    for(int i=h[x];i;i=data[i].next){
        int y=data[i].to;
        if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
        else if(inq[y]) low[x]=min(low[x],dfn[y]);
    }if(low[x]==dfn[x]){
        ++scc;while(1){
            int y=qq.top();qq.pop();inq[y]=0;
            bel[y]=scc;if(y==x) break;
        }
    }
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();int K=read();
    while(m--){
        int x=read(),y=read();
        add(x<<1|1,y<<1);add(y<<1|1,x<<1);
    }tot=n;
    while(K--){
        m=read();
        for(int i=1;i<=m;++i){
            int x=read(),y=tot+i;
            if(i==1){
                add(x<<1|1,y<<1|1);
            }else{
                add(y<<1|1,(y-1)<<1|1);
                add((y-1)<<1,y<<1);add(x<<1,(y-1)<<1|1);
            }add(x<<1,y<<1);add(y<<1|1,x<<1|1);
            y+=m;
            if(i==m){
                add(x<<1|1,y<<1|1);
            }else{
                add(y<<1|1,(y+1)<<1|1);
                add((y+1)<<1,y<<1);add(x<<1,(y+1)<<1|1);
            }add(x<<1,y<<1);add(y<<1|1,x<<1|1);
        }tot+=m+m;
    }for(int i=2;i<=tot*2+1;++i) if(!dfn[i]) tarjan(i);bool flag=0;
    for(int i=1;i<=tot;++i){
        if(bel[i<<1]==bel[i<<1|1]){flag=1;break;}
    }puts(flag?"NIE":"TAK");
    return 0;
}
阅读更多

没有更多推荐了,返回首页