[loj3561]The short shank; Redemption
记$L_{i}=\max_{1\le j<i,t_{j}+(i-j)\le T}j$,那么第$i$个人不越狱当且仅当$\exists L_{i}\le k<i$使得$k$上放了床垫
换言之,即在$D$个位置放床垫,并最大化$[L_{i},i)$内存在床垫的$i$数量
注意到不存在$L_{i}<L_{j}<i<j$,否则$L_{j}-j$和$L_{i}-i$的大小关系存在矛盾
进一步的,即区间关系仅有包含或相离,对每一个区间将包含其的最小区间作为其父亲,得到一棵森林
此时,问题即选择$D$个叶子,覆盖其到根的路径,长链剖分后取最长的$D$条链即可
细节上,注意特判$L_{i}$不存在和$L_{i}=i$的情况
时间复杂度为$o(n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 2000005 4 vector<int>v0,v[N]; 5 int n,D,T,ans,a[N],st[N],L[N],dep[N],son[N],cnt[N]; 6 int read(){ 7 int x=0; 8 char c=getchar(); 9 while ((c<'0')||(c>'9'))c=getchar(); 10 while ((c>='0')&&(c<='9')){ 11 x=x*10+c-'0'; 12 c=getchar(); 13 } 14 return x; 15 } 16 void dfs1(int k){ 17 dep[k]=1; 18 for(int i=0;i<v[k].size();i++){ 19 dfs1(v[k][i]); 20 if (dep[v[k][i]]+1>dep[k]){ 21 dep[k]=dep[v[k][i]]+1; 22 son[k]=v[k][i]; 23 } 24 } 25 } 26 void dfs2(int k,int t){ 27 if (son[k])dfs2(son[k],t); 28 if (k==t)v0.push_back(dep[k]); 29 for(int i=0;i<v[k].size();i++) 30 if (v[k][i]!=son[k])dfs2(v[k][i],v[k][i]); 31 } 32 int main(){ 33 n=read(),D=read(),T=read(); 34 for(int i=1;i<=n;i++)a[i]=read()-i; 35 for(int i=1;i<=n;i++){ 36 while ((st[0])&&(a[st[st[0]]]>min(a[i],T-i)))st[0]--; 37 if (a[i]<=T-i)st[++st[0]]=i; 38 if (st[0])L[i]=st[st[0]]; 39 else ans++,L[i]=i; 40 } 41 st[0]=0; 42 for(int i=n;i;i--){ 43 if (L[i]==i)continue; 44 while ((st[0])&&(L[st[st[0]]]>L[i]))st[0]--; 45 if (st[0])v[st[st[0]]].push_back(i); 46 st[++st[0]]=i; 47 } 48 for(int i=n;i;i--) 49 if ((L[i]<i)&&(!dep[i]))dfs1(i),dfs2(i,i); 50 for(int i=0;i<v0.size();i++)cnt[v0[i]]++; 51 for(int i=n;i;i--) 52 while ((D)&&(cnt[i]))D--,cnt[i]--,ans+=i; 53 printf("%d\n",n-ans); 54 return 0; 55 }