【BZOJ4444】國旗計劃 - 決策單調性
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號邊防戰士必須參加的前提下至少需要多少名邊防戰士才能順利地完成國旗計劃.
HINT
$n\leq 2\times 10^5,M<10^9,1\leq C_i,D_i\leq M$
題解:
一個環的題容易想到倍長變成鏈,然後對於點$i$向右跑到了點$i+m$就算跑完了;
考慮算出每個點向右一次能傳遞到的最右端的節點,設為$next[i]$,將所有人按照左端點排序,找到左端點不超過當前節點的右端點最大的即可;由於排序後左節點單調上升,所以找到的人也肯定單調向右,所以可以直接用一個指針掃,線性復雜度計算;
然後一個顯然的做法是倍增,用類似樹上倍增的方法維護每個$i$到$next[i]$的這個類似樹的結構,然後直接跑就行了。
但是由於本人過於傻逼,以為倍增完還要二分找答案,算了算40w兩個$log$正好1.2S,然後不知道誰說這題一秒時限肯定會卡我(實際上這題後來改成了兩秒並且倍增只有一個$log$),於是自爆的cha掉了這個算法。。。
進一步看這棵next樹,設當前節點為$x$,$next[x]$能走到的最遠節點為$k$,那麽顯然$next[x]$和$k$之間的距離至少為$m$,所以$x$到$k$的距離一定大於$m$,所以$x$能走到的最遠節點$k‘$一定在$next[x]$和$k$之間,如圖:
這個性質就是說,每次做出的決策點肯定不會比上一次(父節點)的決策點更右,即深度是保持不降的,那麽就可以用雙端隊列暴力維護進出隊,統計答案就是$dep[x]-dep[k]+1$。
後面的部分只需要一個dfs,所以時間復雜度是線性的,但是前面要排序,所以是$O(nlogn)$。。。
代碼:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 using namespace std;
7 typedef long long ll;
8 struct edge{
9 int v,next;
10 }a[500001];
11 struct task{
12 ll l,r;
13 int id;
14 }q[500001];
15 int n,m,p=1,tot=0,dep[500001],ans[500001],head[500001],hd,ta,qq[2000001];
16 ll l,r;
17 bool cmp(task a,task b){
18 return a.l<b.l;
19 }
20 void add(int u,int v){
21 a[++tot].v=v;
22 a[tot].next=head[u];
23 head[u]=tot;
24 }
25 void dfs(int u,int now,int dpt){
26 dep[u]=dpt;
27 qq[++ta]=u;
28 if(q[u].id){
29 while(now<ta&&q[qq[now+1]].r>=q[u].l+m)now++;
30 ans[q[u].id]=dep[u]-dep[qq[now]]+1;
31 }
32 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
33 int v=a[tmp].v;
34 dfs(v,now,dpt+1);
35 }
36 ta--;
37 }
38 int main(){
39 memset(head,-1,sizeof(head));
40 scanf("%d%d",&n,&m);
41 for(int i=1;i<=n;i++){
42 scanf("%d%d",&l,&r);
43 if(l>r)r+=m;
44 q[i].l=l;
45 q[i].r=r;
46 q[i].id=i;
47 q[i+n].l=l+m;
48 q[i+n].r=r+m;
49 q[i+n].id=0;
50 }
51 sort(q+1,q+n+1,cmp);
52 for(int i=1;i<n*2;i++){
53 while(p<n*2&&q[p+1].l<=q[i].r)p++;
54 add(p,i);
55 }
56 dfs(n*2,1,1);
57 for(int i=1;i<=n;i++)printf("%d ",ans[i]);
58 return 0;
59 }
【BZOJ4444】國旗計劃 - 決策單調性