BZOJ 3495: PA2010 Riddle
Posted 北屿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3495: PA2010 Riddle相关的知识,希望对你有一定的参考价值。
Description
\(n\)个城市,\(k\)个国家,\(m\)条边,边两边至少有一个首都,问是否存在合法解。\(1\leqslant k\leqslant n,m\leqslant 10^6\)
Solution
2-SAT.
有几个限制条件一起列上...
这样建图是\(O(n^2)\)的...用前缀和表示来限制一下首都个数...
1.一个点不是首都,那么另一个点一定是首都.
2.前缀和为1,这个点一定为0.
3.这个点为1,前缀和一定为1.
4.这个点为1,前一个点一定为0.
5.这个位置的前缀和为0,前一个位置的前缀和一定为0.
6.这个位置的前缀和为1,后一个位置的前缀和一定为1.
然后缩点判断一下...用vector被卡常了...
Code
/************************************************************** Problem: 3495 User: BeiYu Language: C++ Result: Accepted Time:20436 ms Memory:350776 kb ****************************************************************/ #include <bits/stdc++.h> using namespace std; const int N = 4000050; const int M = 20000050; inline int in(int x=0,char c=getchar()) { while(c>‘9‘||c<‘0‘) c=getchar(); while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar();return x; } int n,k,m,cp,bp,tp; int a[N]; int b[N],bl[N],dfn[N],low[N],stk[N]; int ep; int nxt[M],tto[M],hd[M]; void AddEdge(int fr,int to) { nxt[++ep]=hd[fr],tto[ep]=to,hd[fr]=ep; } void Tarjan(int u,int fa) { dfn[u]=low[u]=++cp,b[u]=1,stk[++tp]=u; for(int i=hd[u],v;i;i=nxt[i]) { v=tto[i]; if(!dfn[v]) Tarjan(v,u),low[u]=min(low[u],low[v]); else if(b[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { for(bp++;;) { int v=stk[tp]; bl[v]=bp,b[v]=0,tp--; if(u==v) break; } } } int main() { n=in(),m=in(),k=in(); for(int i=1;i<=m;i++) { int u=in(),v=in(); AddEdge(u,v+n); AddEdge(v,u+n); } for(int i=1,t,j;i<=k;i++) { for(t=in(),j=1;j<=t;j++) a[j]=in(); for(j=1;j<=t;j++) { if(j+1<=t) AddEdge(a[j+1]+2*n,a[j]+2*n),AddEdge(a[j]+3*n,a[j+1]+3*n), AddEdge(a[j]+3*n,a[j+1]),AddEdge(a[j+1]+n,a[j]+2*n); AddEdge(a[j]+n,a[j]+3*n),AddEdge(a[j]+2*n,a[j]); } } for(int i=1;i<=4*n;i++) if(!dfn[i]) Tarjan(i,i); /* for(int i=1;i<=4*n;i++) { cout<<i<<" --> "; for(int j=0;j<(int)g[i].size();j++) cout<<g[i][j]<<" ";cout<<endl; } for(int i=1;i<=4*n;i++) cout<<dfn[i]<<" ";cout<<endl; for(int i=1;i<=4*n;i++) cout<<low[i]<<" ";cout<<endl; for(int i=1;i<=4*n;i++) cout<<bl[i]<<" ";cout<<endl;*/ for(int i=1;i<=n;i++) if(bl[i]==bl[i+n]) return puts("NIE"),0; for(int i=2*n+1;i<=3*n;i++) if(bl[i]==bl[i+n]) return puts("NIE"),0; return puts("TAK"),0; }
以上是关于BZOJ 3495: PA2010 Riddle的主要内容,如果未能解决你的问题,请参考以下文章