ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Sol.CF1696D

2022-06-27 23:03:46  阅读:164  来源: 互联网

标签:连边 CF1696D ps int pos Sol 最小值 枢纽


赛时寄了,然后本人很气愤,于是写下此篇题解。

(没关系,这可是 \({\color{black}j}{\color{red}{iangly}}\) 江老板都没有做出来的绝世大好题啊!!!)

然而看过题解之后 \(O(n)\) 算法还是一概不会,于是只能思维不够 DS 来凑,然而 D 题撑死也不会有什么奇葩东西,所以就选择了线段树板子来做区间最大和最小值的查询(甚至是静态不带修)(然而是线段树板子打太多导致现在不是很能在静态情况下考虑使用更简单的 ST 表)。

言归正传:我们考虑何时能够连边,题意告诉我们,只有最大值和最小值分别分布在区间两端点处时才可以连边,所以说我们假设 \(a_i=n\) 的位置 \(i\) 不在整个序列的两端,那么我们发现 \(i\) 这个位置把整个序列就好像一道天堑一样划成了两部分,两部分之间可以发现总是无法连边的,而从一部分到另一部分总要经过 \(i\) 这个位置。

我们于是把 \(i\) 这样必经的位置称为“枢纽点”。

我们再考察 \(i\) 左右两边的部分,以左边为例,左边的最小值所在位置同样是一个“枢纽点”,它的两边无法连边,从一边到另一边必须经过“枢纽点”,而且,还有一件重要的事情是,这个最小值的“枢纽点”恰好(而且是一定)可以和 \(n\) 的“枢纽点”连边。

所以最小值“枢纽点”的右半部分就不用再考虑了,显然走到它里面的节点会使答案更劣。

所以我们可以以此类推下去,从 \(n\) 对应的的枢纽点出发,找其左半部分的最小值,作为新的“枢纽点”,连边(答案 +1 ),然后再在最小值对应的“枢纽点”左边找一个最大值……再找一个最小值……,如此往复循环下去,直到位置 1 作为最后一个要找的“枢纽点”被连边。

对于 \(n\) 对应的的枢纽点的右半部分,处理方式同理。

	int a[250010];
	int pos[250010];
	int mx[250010<<2];
	int mn[250010<<2];
	
	void pushup(int x){
		mx[x]=max(mx[x<<1],mx[x<<1|1]);
		mn[x]=min(mn[x<<1],mn[x<<1|1]);
	}
	
	void build(int x,int l,int r){
		if(l==r){
			mx[x]=mn[x]=a[l];
			return;
		}
		//mx[x]=0;mn[x]=0x3f3f3f3f;
		int mid=(l+r)>>1;
		build(x<<1,l,mid);
		build(x<<1|1,mid+1,r);
		pushup(x);
	}
	
	pii query(int x,int l,int r,int tl,int tr){
		if(tl<=l&&r<=tr){
			return mp(mx[x],mn[x]);
		}
		int mid=(l+r)>>1;
		pii res=mp(0,0x3f3f3f3f);
		if(tl<=mid){
			pii tmp=query(x<<1,l,mid,tl,tr);
			res.first=max(res.first,tmp.first);
			res.second=min(res.second,tmp.second);
		}
		if(mid<tr){
			pii tmp=query(x<<1|1,mid+1,r,tl,tr);
			res.first=max(res.first,tmp.first);
			res.second=min(res.second,tmp.second);
		}
		return res;
	}
	
	int T;
	int n;
	
	void main(){
		cin>>T;
		while(T--){
			cin>>n;
			for(int i=1;i<=n;i++){
				cin>>a[i];
				pos[a[i]]=i;
			}
		
			int ans=0;
			build(1,1,n);
		
			int ps=pos[n]-1,fd=1;
			while(ps){
				ans++;
				pii tmp=query(1,1,n,1,ps);
				ps=(fd)?(pos[tmp.second]-1):(pos[tmp.first]-1);
				fd^=1;
			}
			ps=pos[n]+1,fd=1;
			while(ps<=n){
				ans++;
				pii tmp=query(1,1,n,ps,n);
				ps=(fd)?(pos[tmp.second]+1):(pos[tmp.first]+1);
				fd^=1;
			}
			cout<<ans<<endl;
		}
	}

标签:连边,CF1696D,ps,int,pos,Sol,最小值,枢纽
来源: https://www.cnblogs.com/Lucky-Yukikaze/p/16417869.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有