P5913 题解
honglan0301 · · 题解
题目分析
一个渐进更优但是在这题数据范围下跟
首先我们观察
-
把原图分成多个不连通的子图(求连通块),然后分别检查各个子图。
-
要么把反图分成多个不连通的子图(求反图连通块),然后分别检查各个子图的反图。
分析时间复杂度。单次操作
接下来考虑优化拆分的步骤。发现我们应该不同情况差别对待地对操作
代码
实现可见下面代码,感觉还算简洁。
/*
author: PEKKA_l
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <vector>
using namespace std;
#define pb push_back
int T,n,m,u,v;
vector <int> e[10005];
unordered_map <int,int> s;
bool isb(int x,int y) {if(x>y) swap(x,y); return s.count(x*20000+y);}
int zta[10005],ztb[10005],ztc[10005],cntb,cntc,sza[10005],szc[10005];
int nowb[10005],nxt[20005],frm[20005];
queue <int> Q;
void ins(int k,int x) {nxt[nowb[k]]=x; frm[x]=nowb[k]; nowb[k]=x;}
void del(int x) {nxt[frm[x]]=nxt[x]; frm[nxt[x]]=frm[x]; }
void bfs(int x,int k)
{
Q.push(x); ztb[x]=cntb; ins(ztb[x],x);
while(!Q.empty())
{
int nr=Q.front(); Q.pop();
for(auto i:e[nr]) {if(!ztb[i]&&zta[i]==k) {ztb[i]=cntb; Q.push(i); ins(ztb[i],i);}}
}
}
void bfs2(int x,int k)
{
Q.push(x); ztc[x]=cntc; szc[cntc]++; del(x);
while(!Q.empty())
{
int nr=Q.front(); Q.pop();
for(int i=nxt[k+10000];i;i=nxt[i])
{
if(!isb(nr,i)) {ztc[i]=cntc; szc[cntc]++; del(i); Q.push(i);}
}
}
}
void czc(int k) {while(nxt[k+10000]) {int nr=nxt[k+10000]; cntc++; bfs2(nr,k);}}
signed main()
{
cin>>T;
while(T--)
{
cin>>n>>m; s.clear(); for(int i=1;i<=n;i++) e[i].clear();
for(int i=1;i<=m;i++) {cin>>u>>v; if(u>v) swap(u,v); e[u].pb(v); e[v].pb(u); s[u*20000+v]=1;}
for(int i=1;i<=n;i++) zta[i]=1; sza[1]=n;
while(1)
{
memset(ztb,0,sizeof(ztb)); cntb=0; for(int i=1;i<=n;i++) nowb[i]=i+10000;
memset(nxt,0,sizeof(nxt)); memset(frm,0,sizeof(frm));
for(int i=1;i<=n;i++) if(!ztb[i]) {cntb++; bfs(i,zta[i]);}
memset(ztc,0,sizeof(ztc)); cntc=0; memset(szc,0,sizeof(szc));
for(int i=1;i<=cntb;i++) czc(i);
bool yes=1,no=0;
for(int i=1;i<=n;i++)
{
if(sza[zta[i]]==szc[ztc[i]]) no=1;
if(szc[ztc[i]]>2) yes=0;
}
if(no) {cout<<"NIE"<<endl; break;}
if(yes) {cout<<"TAK"<<endl; break;}
memcpy(zta,ztc,sizeof(ztc)); memcpy(sza,szc,sizeof(szc));
}
}
}