我们把每个点当不当首部作为两种选择,得到了一个很显然的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;
}