bzoj3495

时间:2024-04-17 21:36:00

题解:

对于每一条边的两段都有,很简单

然后处理国家

容易发现前缀和为1

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
inline char nc()
{
static char buf[],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,,stdin),p1==p2)
?EOF:*p1++;
}
int red()
{
int res=,f=;char ch=nc();
while (ch<''||''<ch) {if (ch=='-') f=-f;ch=nc();}
while (''<=ch&&ch<='') res=res*+ch-,ch=nc();
return res*f;
}
const int N=;
int n,e,m,pre[N],tot,lnk[N],son[N*],nxt[N*];
void add(int x,int y){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}
int dfn[N],low[N],stk[N],scc[N],Tim,instk[N];
void tarjan(int x)
{
stk[++stk[]]=x;instk[x]=;
dfn[x]=low[x]=++Tim;
for (int j=lnk[x];j;j=nxt[j])
if (!dfn[son[j]]) tarjan(son[j]),low[x]=min(low[x],low[son[j]]);
else if (instk[son[j]]) low[x]=min(low[x],dfn[son[j]]);
if (low[x]==dfn[x])
{
scc[]++;
while (stk[stk[]+]!=x)
instk[stk[stk[]]]=,scc[stk[stk[]--]]=scc[];
}
}
int main()
{
n=red();e=red(),m=red();
for (int i=,x,y;i<=e;i++)
x=red(),y=red(),add(*x+,*y),add(*y+,*x);
for (int i=;i<=m;i++)
{
int k=red(),lst=red();
for (int j=,x;j<k;j++) x=red(),pre[x]=lst,lst=x;
}
for (int i=;i<=n;i++)
{
add(*i,*i+),add(*i+,*i+);
if (pre[i])
{
int j=pre[i];
add(*j+,*i+);add(*i+,*j+);
add(*j+,*i+);add(*i,*j+);
}
}
Tim=;int N=*n+;
for (int i=;i<=N;i++)
if (!dfn[i]) tarjan(i);
for (int i=;i<=N;i++)
if (scc[i]==scc[i^]) return printf("NIE"),;
printf("TAK");
return ;
}

相关文章