[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;
}
//不对,必须要让外面的去连里面的,因为一个大的可能会连好几个小的,这样就寄掉了
//因为小的连大的会有多个父亲 
posted @ 2022-10-09 21:37  半口学气!  阅读(34)  评论(1编辑  收藏  举报