1. 程式人生 > >BZOJ 4444: [Scoi2015]國旗計劃

BZOJ 4444: [Scoi2015]國旗計劃

bool urn 題目 edge 參加 sam sca i++ div

Description

A國正在開展一項偉大的計劃——國旗計劃。這項計劃的內容是邊防戰士手舉國旗環繞邊境線奔襲一圈。這 項計劃需要多名邊防戰士以接力的形式共同完成,為此,國土安全局已經挑選了N名優秀的邊防戰上作為這 項計劃的候選人。 A國幅員遼闊,邊境線上設有M個邊防站,順時針編號1至M。每名邊防戰士常駐兩個邊防站,並且善於 在這兩個邊防站之間長途奔襲,我們稱這兩個邊防站之間的路程是這個邊防戰士的奔襲區間。n名邊防戰士 都是精心挑選的,身體素質極佳,所以每名邊防戰士的奔襲區間都不會被其他邊防戰士的奔襲區間所包含。 現在,國十安全局局長希望知道,至少需要多少名邊防戰士,才能使得他們的奔襲區間覆蓋全部的邊境線, 從而順利地完成國旗計劃。不僅如此,安全局局長還希望知道更詳細的信息:對於每一名邊防戰士,在他必 須參加國旗計劃的前提下,至少需要多少名邊防戰士才能覆蓋全部邊境線,從而順利地完成國旗計劃。

Input

第1行,包含2個正整數N,M,分別表示邊防戰士數量和邊防站數量。 隨後n行,每行包含2個正整數。其中第i行包含的兩個正整數Ci、Di分別表示i號邊防戰士常駐的兩個邊防站編號, Ci號邊防站沿順時針方向至Di號邊防站力他的奔襲區間。數據保證整個邊境線都是可被覆蓋的。

Output

輸出數據僅1行,需要包含n個正整數。其中,第j個正整數表示j號邊防戰士必須參加的前提下至少需要 多少名邊防戰士才能順利地完成國旗計劃

Sample Input

4 8
2 5
4 7
6 1
7 3

Sample Output

3 3 4 3

HINT

n≤2×10^5,M< 10^9,1≤Ci,Di≤M

題解:   感覺這個題目十分巧妙。   首先我們先斷環為鏈,那麽對於i,我們只要走到i+m就走完了一周。   首先考慮預處理出數組f[i]表示和i這個區間有交並且右端點最遠的區間編號,這個按照有斷點排序之後就可以On搞出來,當然這也是因為題目沒有相互包含的區間的關系。   那麽考慮轉化圖論問題,從i向fi連邊,那麽顯然就會形成一棵樹,我們只要不斷得跳爸爸,一直到區間i的有端點>=l+m就可以了,顯然可以寫一個倍增加速這個過程,但可以部分其實可以On做。   想一想,如果我們從樹頂,自上而下進行決策,那麽就會有一個決策單調性,即:兒子的ans一定在爸爸的ans和爸爸之間,那麽我們就維護一個棧,記錄可能成為答案的點就可以了。 代碼:
#include <cstdio>
#include 
<iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #define MAXN 400010 using namespace std; struct edge{ int first; int next; int to; }a[MAXN*2]; struct qvjian{ int l,r,id; bool operator < (const qvjian &x)const{ return l<x.l; } }q[MAXN]; int dep[MAXN],s[MAXN],tail=0; int n,m,ans[MAXN],num=0; void addedge(int from,int to){ a[++num].to=to; a[num].next=a[from].first; a[from].first=num; } void dfs(int now,int f,int head){ dep[now]=dep[f]+1;s[++tail]=now; if(q[now].id!=0){ while(head<tail&&q[s[head+1]].r>=q[now].l+m) head++; ans[q[now].id]=dep[now]-dep[s[head]]+1; } for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; dfs(to,now,head); } tail--; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ int l,r; scanf("%d%d",&l,&r),q[i].id=i; if(l>r) r+=m; q[i].l=l,q[i].r=r; q[i+n].l=q[i].l+m,q[i+n].r=q[i].r+m,q[i+n].id=0; } int now=1; sort(q+1,q+2*n+1); for(int i=1;i<2*n;i++){ while(now<2*n&&q[i].r>=q[now+1].l) now++; addedge(now,i); } dfs(2*n,0,1); for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }

BZOJ 4444: [Scoi2015]國旗計劃