1. 程式人生 > >圖論訓練 車站分級 [資料結構優化建邊][拓撲排序]

圖論訓練 車站分級 [資料結構優化建邊][拓撲排序]

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; }