[BalticOI2021Day2T1]The short shank
[BalticOI2021Day2T1]The short shank
真的会谢,就我是个傻逼去写长链剖分,直接成最慢的🤡
记Li为满足a[j]+i-j<=T的最大的j
如果为自己就肯定会造反,如果不存在就肯定不会造反
然后会发现L[i]~i这些区间是不会相交的,很容易发现不满足L的定义
所以只会包含和分离
就可以把一个i代表的区间向包含的区间建边,不可以反过来,不然就会有多个爸爸,因为一个大区间可能会包含多个小区间
哎,相当于找D个最长链,在叶子节点的区间上放一个板就好了
#include<bits/stdc++.h>
using namespace std;
int a[2000010],L[2000010]/*max(j):(a[j]+i-j<=T)*/;
vector<int>st,e[2000010];//往它包含的区间建边
multiset<int>ans;
int fa[2000010],dep[2000010],Max[2000010],son[2000010];
void dfs(int x,int fa){
Max[x]=dep[x]=dep[fa]+1;
for(int v:e[x]){
dfs(v,x);
if(Max[v]>Max[son[x]]){
son[x]=v;
Max[x]=Max[v];
}
}
}
void dfs2(int x,int tp){
if(tp==x)ans.insert(Max[x]-dep[tp]+1);
if(son[x])dfs2(son[x],tp);
for(int v:e[x]){
if(v!=son[x])dfs2(v,v);
}
}
int main(){
int n,D,T;
scanf("%d%d%d",&n,&D,&T);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int No=0;
for(int i=1;i<=n;i++){
while(st.size()&&a[st.back()]-st.back()+i>T)st.pop_back();
if(a[i]<=T)st.push_back(i);
if(st.size())L[i]=st.back();
else No++;
}
while(st.size())st.pop_back();
for(int i=n;i>=1;i--){
if(L[i]==i||!L[i])continue;
while(st.size()&&L[st.back()]>L[i])st.pop_back();
if(st.size())e[st.back()].push_back(i);
st.push_back(i);
}
for(int i=n;i>=1;i--){
if(L[i]==i||!L[i])continue;
if(!dep[i])dfs(i,0),dfs2(i,i);
}
while(D--){
No+=*(--ans.end());
ans.erase(ans.find(*(--ans.end())));
}
printf("%d\n",n-No);
return 0;
}
//不对,必须要让外面的去连里面的,因为一个大的可能会连好几个小的,这样就寄掉了
//因为小的连大的会有多个父亲