[luogu1983] 车站分级
妙啊……
很容易想到建个图,然后跑一下拓扑排序,看看有几层就行了。但是会发现连边的代价是平方。
所以可以建立一个虚点,将层与层之间的所有边汇集同一个点上。然后就只需要线性的代价就可以做了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 2005
struct edge{
int v,next;
}G[MAXN*MAXN];
struct queue{
int q[MAXN],head,tail;
queue():head(1),tail(0){}
void pop(){
head++;
}
int front(){
return q[head];
}
void push(int x){
q[++tail] = x;
}
bool empty(){
return head>tail;
}
}q;
int head[MAXN],_in[MAXN];
int a[MAXN],vis[MAXN];
int N,M,tot = 0;
inline void add(int u,int v){
G[++tot].v = v;G[tot].next = head[u];head[u] = tot;
}
void extand(int u){
for(register int i=head[u];i;i=G[i].next){
int v = G[i].v;
_in[v]--;
if(_in[v]==0){
if(v>N)extand(v);
else q.push(v);
}
}
}
int main(){
scanf("%d%d",&N,&M);
std::memset(head,0,sizeof(head));
std::memset(_in,0,sizeof(_in));
std::memset(vis,0,sizeof(vis));
int num;
for(register int i=1;i<=M;++i){
scanf("%d",&num);
for(register int j=1;j<=num;++j){
scanf("%d",&a[j]);
vis[a[j]] = i;
}
for(register int j=a[1];j<=a[num];++j){
if(vis[j]!=i){
add(N+i,j);
_in[j]++;
}
else{
add(j,N+i);
_in[N+i]++;
}
}
}
for(register int i=1;i<=N;++i){
if(_in[i]==0)q.push(i);
}
int count = 0;
while(!q.empty()){
count++;
int l = q.head;
int r = q.tail;
for(register int k=l;k<=r;++k){
int u = q.front();q.pop();
extand(u);
}
}
printf("%d",count);
return 0;
}