圖論訓練 車站分級 [資料結構優化建邊][拓撲排序]
阿新 • • 發佈:2019-01-22
NOIP普及組原題瘋狂加難度的hard版
車站分級(c.cpp,0.5s, 256MB)
【描述】
一條單向的鐵路線上,依次有編號為 1, 2, …, n 的 n 個火車站。每個火車站都有一個級別,最低為 1 級。現有若干趟車次在這條線路上行駛,每一趟都滿足如下要求:如果這趟車次停靠了火車站 x,則始發站、終點站之間所有級別大於等於火車站 x 的都必須停靠。(注意:起始站和終點站自然也算作事先已知需要停靠的站點)現有 m 趟車次的執行情況(全部滿足要求),試推算這 n 個火車站至少分為幾個不同的級別。
【輸入】
第一行包含 2 個正整數 n, m。
接下來 m 行,首先是一個正整數 si(2 ≤ si ≤ n),表示第 i 趟車次有 si 個停靠站;接下來有 si個正整數,表示所有停靠站的編號,從小到大排列。每兩個數之間用一個空格隔開。輸入保證所有的車次都滿足要求。
【輸出】
一行一個整數,表示車站最少劃分的級別數。
【樣例輸入】
9 3
4 1 3 5 6
3 3 5 6
3 1 5 9
【樣例輸出】
3
【限制與約定】
對於10%的資料,n,m<=100。
對於40%的資料,n,m<=5000。
對於100%的資料,n,m<=100000,所有si的和不超過100000。
思考
這玩意兒看著就很瘋狂,用到了建立虛點的優化,然後發現建邊超時了,為了防止這種情況發生,然後就以資料結構(or 倍增建邊……)優化,一邊頂多條邊。
同時線段樹的上下層節點也互相連邊,關聯虛點。
#define PN "c"
#include <cstdio>
#include <cstring>
#include <algorithm>
const int SIZ = 600000 + 1000;
const int M = 6000000 + 100000;
struct EDGE {int v,upre;}g[M];
int head[SIZ], ne = 0;
int in[SIZ], level[SIZ], pos[SIZ], idc;
bool mark[SIZ];
inline void adde(int u,int v) {in[v]++;g[++ne]=(EDGE){v,head[u]};head[u]=ne;}
#include <queue>
std::queue<int> q;
int n;
void solve() {
int u, i, v, ans = 1;q.push(0);
for( i = 1; i <= n; i++ ) if(!in[pos[i]]) q.push(pos[i]), level[pos[i]]=1;
while(!q.empty()) {
u = q.front();q.pop();
for ( i = head[u], v; i; i = g[i].upre ) {
v = g[i].v;
in[v]--;if(!in[v]) q.push(v);
level[v]=std::max(level[v],level[u]+mark[v]);
ans=std::max(ans,level[v]);
}
}
printf("%d\n",ans);
}
struct NODE {
int id;
NODE *ls, *rs;
} pool[SIZ], *tail=pool, *root;
NODE *build(int lf,int rg) {
NODE *nd=tail++;nd->id=++idc;
if(lf==rg) mark[nd->id]=1, pos[lf]=nd->id;
else {
int mid=(lf+rg)>>1;
nd->ls=build(lf,mid);
adde(nd->ls->id,nd->id);
nd->rs=build(mid+1,rg);
adde(nd->rs->id,nd->id);
}
return nd;
}
void addedge(NODE *nd,int lf,int rg,int L,int R,int linkpoint) {
if(L<=lf&&rg<=R) {
adde(nd->id,linkpoint);
return ;
}
int mid=(lf+rg)>>1;
if(L<=mid) addedge(nd->ls,lf,mid,L,R,linkpoint);
if(mid<R) addedge(nd->rs,mid+1,rg,L,R,linkpoint);
}
int main() {
freopen(PN".in","r",stdin);
freopen(PN".out","w",stdout);
int m;
scanf("%d%d",&n,&m);
root=build(1,n);
for( int i = 1, j, s, last, now, linkpoint; i <= m; i++ ) {
scanf("%d%d",&s,&last);linkpoint=++idc;adde(0,linkpoint);adde(linkpoint,pos[last]);
for( j = 1; j < s; j++ ) {
scanf("%d",&now);adde(linkpoint,pos[now]);
addedge(root,1,n,last+1,now-1,linkpoint);
last = now;
}
}
solve();
return 0;
}