首页 > 其他分享 >冒险数据结构:峰谷序列(动态序列查找问题)

冒险数据结构:峰谷序列(动态序列查找问题)

时间:2025-01-10 21:02:06浏览次数:3  
标签:p2 loc cnt p1 峰谷 yy ff 序列 数据结构

先考虑这么一个问题:

        如何求出一个序列在所有位置上的各个元素的前面和后面第一个比它小的元素位置。

显然这个问题可以用单调栈来解决。

        如上图所示,维护一个单调递增的序列,每当栈顶>当前元素时,就抛出栈顶,这时就找到了栈顶元素后面第一个小于它的元素,以此循环,就能找到所有位置上的元素后面第一个比它小的元素位置。要找到前面第一个小的元素位置只要反正入栈即可。

        每个元素至多入栈和出栈各一次,时间复杂程度为O(N)。

  ----------------------------------------------------------------------------------------------------------------------------

然后我们考虑这个问题:

        如何求出一个动态序列在询问位置上的元素在询问时刻的前面和后面第一个比它小的元素位置。(每次插入元素的位置可在序列的前中后的任意位置)。

        若每次询问时都跑一边单调栈,时间复杂程度为(NQ),其中Q为询问次数。

现考虑以下数据结构:

        将每一个连续的上升或下降序列定义为一个breand,breand的指针指向峰顶和谷底(t1,t2)

        每个元素(圆点)有4个指针p1,p2,le,ri,若在上升序列用p2指向breand,下降用p1,峰顶和谷地可以同时使用p1,p2;用le,ri指向相邻元素。

        每个breand都是有序不重复序列,使用set结构存储元素大小,查找元素大小时间复杂度为O(logn)。(连续相同的元素会合在一起为一个元素,元素.size++)

下面给出s1元素(左下角箭头所指元素)查找后面第一个小于它的元素(s10)的位置的过程:

        s1-->s1.p2-->breand(1)-->t2-->s4-->s4.p1-->breand(2)-->t1-->s6

        -->(比较s6>=s1)-->s6.p2-->breand(3)-->t2-->s8-->s8.p1-->breand(4)

        -->t1->s10-->(比较s10<s1)-->*(--breand(4).set.lower_bound(s1))-->s10。

因此查完所有询问元素的复杂程度为O(Q(K+logM))。

其中K为直接通过谷底比较跳过的breand数,M为最后一个breand的元素个数。

下面给出该数据结构的元素插入过程(主要分4种情况):

(1)中间不破顺序插入

(2)中间破顺序插入

(3)两端不破顺序插入

(4)两端破顺序插入

插入所有元素的复杂程度期望为O( N(logM)^2 )。其中M为breand中的元素个数期望。

因此算法总复杂程度为O(Q(K+logM)+N(logM)^2 )。

其中K为直接通过谷底比较跳过的breand数的期望,M为breand中的元素个数期望,Q为询问次数,N为元素个数。

以下为代码:(插入元素部分的代码占了大部分)(查找的是元素前面和后面最后一个不比它小的元素位置)

struct line
{
	struct po
	{
		ll value,size;
		ll p1=0,p2=0,le,ri;
		ll tag;
		po(ll a=0,ll b=0,ll c=-1,ll d=-1,ll f=0){value=a,size=b,le=c,ri=d,tag=f;}
	};
	struct pa
	{
		ll value,loc;
		pa(ll a,ll b){value=a,loc=b;};
		bool operator<(const pa &b)const
		{
			return value<b.value;
		}
	};
	struct brean
	{
		ll p1=0,p2=0;
		set<pa>se;
	};
	ll len = 0,cnt=0;
	vector<po>s;
	vector<brean>ff;
	set<ll>dk;
	line(ll n) :len(n), s(n + 1), ff(n + 1) {dk.insert(-1);};
	pair<ll,ll> lin_find(ll loc)
	{
		ll le_ve=loc,ri_ve=loc;
		if(s[loc].ri!=-1&&s[loc].value<s[s[loc].ri].value)
		{
			ll yy=s[ff[s[loc].p2].p2].p1;
			while(ff[yy].p1&&s[ff[yy].p1].value>=s[loc].value)
				yy=s[ff[s[ff[yy].p1].p2].p2].p1;
			if(ff[yy].p1)
				ri_ve=(*(ff[yy].se.lower_bound(pa(s[loc].value,loc)))).loc;
			else
				ri_ve=ff[yy].p2;
		}
		if(s[loc].le!=-1&&s[loc].value<s[s[loc].le].value)
		{
			ll yy=s[ff[s[loc].p1].p2].p2;
			while(ff[yy].p1&&s[ff[yy].p1].value>=s[loc].value)
				yy=s[ff[s[ff[yy].p1].p1].p2].p2;
			if(ff[yy].p1)
				le_ve=(*(ff[yy].se.lower_bound(pa(s[loc].value,loc)))).loc;
			else
				le_ve=ff[yy].p2;
		}
		pair<ll,ll> a1(le_ve,ri_ve);
		return a1;
		
	}
	void lin_insert(ll loc,ll ve)
	{
		auto p1=dk.lower_bound(loc);
		auto p3=p1;
		auto p2=--p3;
		if(p1==dk.end()&&p2==dk.begin())
		{
			s[loc]=po(ve,1,-1,-1,3);
			dk.insert(loc);
			return;
		}
		if(p1!=dk.end()&&s[*p1].value==ve)
		{
			s[*p1].size++;
			return;
		}
		if(p2!=dk.begin()&&s[*p2].value==ve)
		{
			s[*p2].size++;
			return;
		}
		if(ve>max(p1!=dk.end()?s[*p1].value:-1e10,p2!=dk.begin()?s[*p2].value:-1e10))
		{
			if(p1!=dk.end()&&(s[*p1].tag==2||s[*p1].tag==3))
			{
				s[loc]=po(ve,1,p2!=dk.begin()?*p2:-1,*p1,2);
				s[*p1].le=loc;
				if(p2!=dk.begin())s[*p2].ri=loc;
				s[loc].p1=s[*p1].p1;
				s[loc].p2=s[*p1].p2;
				if(s[*p1].p1)
				{
					ff[s[*p1].p1].p2=loc;
					ff[s[*p1].p1].se.insert(pa(ve,loc));
				}
				else
				{
					ff[++cnt].p2=loc;
					ff[cnt].p1=*p1;
					s[loc].p1=s[*p1].p1=cnt;
					ff[cnt].se.insert(pa(ve,loc));
					ff[cnt].se.insert(pa(s[*p1].value,*p1));
				}
				if(s[*p1].p2)
				{
					ff[s[*p1].p2].p2=loc;
					ff[s[*p1].p2].se.erase(pa(s[*p1].value,*p1));
					ff[s[*p1].p2].se.insert(pa(ve,loc));
					s[*p1].p2=0;
				}
				if(s[*p1].ri!=-1)
					s[*p1].tag=0;
				else
					s[*p1].tag=1;
				dk.insert(loc);
				return;
			}
			if(p2!=dk.begin()&&(s[*p2].tag==2||s[*p2].tag==3))
			{
				s[loc]=po(ve,1,*p2,p1!=dk.end()?*p1:-1,2);
				s[*p2].ri=loc;
				if(p1!=dk.end())s[*p1].le=loc;
				s[loc].p1=s[*p2].p1;
				s[loc].p2=s[*p2].p2;
				if(s[*p2].p2)
				{
					ff[s[*p2].p2].p2=loc;
					ff[s[*p2].p2].se.insert(pa(ve,loc));
				}
				else
				{
					ff[++cnt].p2=loc;
					ff[cnt].p1=*p2;
					s[loc].p2=s[*p2].p2=cnt;
					ff[cnt].se.insert(pa(ve,loc));
					ff[cnt].se.insert(pa(s[*p2].value,*p2));
				}
				if(s[*p2].p1)
				{
					ff[s[*p2].p1].p2=loc;
					ff[s[*p2].p1].se.erase(pa(s[*p2].value,*p2));
					ff[s[*p2].p1].se.insert(pa(ve,loc));
					s[*p1].p1=0;
				}
				if(s[*p2].le!=-1)
					s[*p2].tag=0;
				else
					s[*p2].tag=1;
				dk.insert(loc);
				return;
			}
			if(p1!=dk.end()&&p2!=dk.begin())
			{
				cnt++;
				ff[cnt].p2=loc;
				s[loc]=po(ve,1,*p2,*p1,2);
				s[*p2].ri=s[*p1].le=loc;
				if(s[*p1].value>s[*p2].value)
				{
					s[loc].p2=cnt;
					ff[cnt].p1=ff[s[*p2].p2].p1;
					ff[cnt].se.insert(pa(ve,loc));
					ll yy=*p2;
					while(yy!=ff[cnt].p1)
					{
						ff[s[yy].p2].se.erase(pa(s[yy].value,yy));
						ff[cnt].se.insert(pa(s[yy].value,yy));
						s[yy].p2=cnt;
						yy=s[yy].le;
					}
					ff[s[yy].p2].se.erase(pa(s[yy].value,yy));
					ff[cnt].se.insert(pa(s[yy].value,yy));
					s[yy].p2=cnt;
					ff[++cnt].p2=loc;
					ff[cnt].p1=*p1;
					ff[cnt].se.insert(pa(ve,loc));
					ff[cnt].se.insert(pa(s[*p1].value,*p1));
					s[loc].p1=s[*p1].p1=cnt;
					s[*p1].tag=1;
				}
				else
				{
					s[loc].p1=cnt;
					ff[cnt].p1=ff[s[*p1].p1].p1;
					ff[cnt].se.insert(pa(ve,loc));
					ll yy=*p1;
					while(yy!=ff[cnt].p1)
					{
						ff[s[yy].p1].se.erase(pa(s[yy].value,yy));
						ff[cnt].se.insert(pa(s[yy].value,yy));
						s[yy].p1=cnt;
						yy=s[yy].ri;
					}
					ff[s[yy].p1].se.erase(pa(s[yy].value,yy));
					ff[cnt].se.insert(pa(s[yy].value,yy));
					s[yy].p1=cnt;
					ff[++cnt].p2=loc;
					ff[cnt].p1=*p2;
					ff[cnt].se.insert(pa(ve,loc));
					ff[cnt].se.insert(pa(s[*p2].value,*p2));
					s[loc].p2=s[*p2].p2=cnt;
					s[*p2].tag=1;
				}
				dk.insert(loc);
			}
			else if(p1!=dk.end())
			{
				s[loc]=po(ve,1,-1,*p1,2);
				s[*p1].le=loc;
				ff[++cnt].p2=loc;
				ff[cnt].p1=*p1;
				ff[cnt].se.insert(pa(ve,loc));
				ff[cnt].se.insert(pa(s[*p1].value,*p1));
				s[loc].p1=s[*p1].p1=cnt;
				s[*p1].tag=1;
				dk.insert(loc);
			}
			else
			{
				s[loc]=po(ve,1,*p2,-1,2);
				s[*p2].ri=loc;
				ff[++cnt].p2=loc;
				ff[cnt].p1=*p2;
				ff[cnt].se.insert(pa(ve,loc));
				ff[cnt].se.insert(pa(s[*p2].value,*p2));
				s[loc].p2=s[*p2].p2=cnt;
				s[*p2].tag=1;
				dk.insert(loc);
			}		
		}
		else if(ve<min(p1!=dk.end()?s[*p1].value:1e10,p2!=dk.begin()?s[*p2].value:1e10))
		{
			if(p1!=dk.end()&&(s[*p1].tag==1||s[*p1].tag==3))
			{
				s[loc]=po(ve,1,p2!=dk.begin()?*p2:-1,*p1,1);
				s[*p1].le=loc;
				if(p2!=dk.begin())s[*p2].ri=loc;
				s[loc].p1=s[*p1].p1;
				s[loc].p2=s[*p1].p2;
				ff[s[*p1].p1].p1=loc;
				ff[s[*p1].p2].p1=loc;
				if(s[*p1].p2)
				{
					ff[s[*p1].p2].p1=loc;
					ff[s[*p1].p2].se.insert(pa(ve,loc));
				}
				else
				{
					ff[++cnt].p1=loc;
					ff[cnt].p2=*p1;
					s[loc].p2=s[*p2].p2=cnt;
					ff[cnt].se.insert(pa(ve,loc));
					ff[cnt].se.insert(pa(s[*p1].value,*p1));
				}
				if(s[*p1].p1)
				{
					ff[s[*p1].p1].p1=loc;
					ff[s[*p1].p1].se.erase(pa(s[*p1].value,*p1));
					ff[s[*p1].p1].se.insert(pa(ve,loc));
					s[*p1].p1=0;
				}
				if(s[*p1].ri!=-1)
					s[*p1].tag=0;
				else
					s[*p1].tag=2;
				dk.insert(loc);
				return;
			}
			if(p2!=dk.begin()&&(s[*p2].tag==1||s[*p2].tag==3))
			{
				s[loc]=po(ve,1,*p2,p1!=dk.end()?*p1:-1,1);
				s[*p2].ri=loc;
				if(p1!=dk.end())s[*p1].le=loc;
				s[loc].p1=s[*p2].p1;
				s[loc].p2=s[*p2].p2;
				if(s[*p2].p1)
				{
					ff[s[*p2].p1].p1=loc;
					ff[s[*p2].p1].se.insert(pa(ve,loc));
				}
				else
				{
					ff[++cnt].p1=loc;
					ff[cnt].p2=*p2;
					s[loc].p1=s[*p2].p1=cnt;
					ff[cnt].se.insert(pa(ve,loc));
					ff[cnt].se.insert(pa(s[*p2].value,*p2));
				}
				if(s[*p2].p2)
				{
					ff[s[*p2].p2].p1=loc;
					ff[s[*p2].p2].se.erase(pa(s[*p2].value,*p2));
					ff[s[*p2].p2].se.insert(pa(ve,loc));
					s[*p1].p2=0;
				}
				if(s[*p2].le!=-1)
					s[*p2].tag=0;
				else
					s[*p2].tag=2;
				dk.insert(loc);
				return;
			}
			if(p1!=dk.end()&&p2!=dk.begin())
			{
				cnt++;
				ff[cnt].p1=loc;
				s[loc]=po(ve,1,*p2,*p1,1);
				s[*p2].ri=s[*p1].le=loc;
				if(s[*p1].value>s[*p2].value)
				{
					s[loc].p2=cnt;
					ff[cnt].p2=ff[s[*p1].p2].p2;
					ff[s[*p1].p2].p2=*p2;
					ff[cnt].se.insert(pa(ve,loc));
					ll yy=*p1;
					while(yy!=ff[cnt].p2)
					{
						ff[s[yy].p2].se.erase(pa(s[yy].value,yy));
						ff[cnt].se.insert(pa(s[yy].value,yy));
						s[yy].p2=cnt;
						yy=s[yy].ri;
					}
					ff[s[yy].p2].se.erase(pa(s[yy].value,yy));
					ff[cnt].se.insert(pa(s[yy].value,yy));
					s[yy].p2=cnt;
					ff[++cnt].p1=loc;
					ff[cnt].p2=*p2;
					ff[cnt].se.insert(pa(ve,loc));
					ff[cnt].se.insert(pa(s[*p2].value,*p2));
					s[loc].p1=s[*p2].p1=cnt;
					s[*p2].tag=2;
				}
				else
				{
					s[loc].p1=cnt;
					ff[cnt].p2=ff[s[*p2].p1].p2;
					ff[s[*p2].p1].p2=*p1;
					ff[cnt].se.insert(pa(ve,loc));
					ll yy=*p2;
					while(yy!=ff[cnt].p2)
					{
						ff[s[yy].p1].se.erase(pa(s[yy].value,yy));
						ff[cnt].se.insert(pa(s[yy].value,yy));
						s[yy].p1=cnt;
						yy=s[yy].le;
					}
					ff[s[yy].p1].se.erase(pa(s[yy].value,yy));
					ff[cnt].se.insert(pa(s[yy].value,yy));
					s[yy].p1=cnt;
					ff[++cnt].p1=loc;
					ff[cnt].p2=*p1;
					ff[cnt].se.insert(pa(ve,loc));
					ff[cnt].se.insert(pa(s[*p1].value,*p1));
					s[loc].p2=s[*p1].p2=cnt;
					s[*p1].tag=1;
				}
				dk.insert(loc);
			}
			else if(p1!=dk.end())
			{
				s[loc]=po(ve,1,-1,*p1,1);
				s[*p1].le=loc;
				ff[++cnt].p1=loc;
				ff[cnt].p2=*p1;
				ff[cnt].se.insert(pa(ve,loc));
				ff[cnt].se.insert(pa(s[*p1].value,*p1));
				s[loc].p2=s[*p1].p2=cnt;
				s[*p1].tag=2;
				dk.insert(loc);
			}
			else
			{
				s[loc]=po(ve,1,*p2,-1,1);
				s[*p2].ri=loc;
				ff[++cnt].p1=loc;
				ff[cnt].p2=*p2;
				ff[cnt].se.insert(pa(ve,loc));
				ff[cnt].se.insert(pa(s[*p2].value,*p2));
				s[loc].p1=s[*p2].p1=cnt;
				s[*p2].tag=2;
				dk.insert(loc);
			}		
		}
		else
		{
			s[loc]=po(ve,1,*p2,*p1,0);
			s[*p1].le=s[*p2].ri=loc;
			ff[s[*p1].p2].se.insert(pa(ve,loc));
			if(s[*p1].value>s[*p2].value)
				s[loc].p2=s[*p1].p2;
			else
				s[loc].p1=s[*p1].p1;
			dk.insert(loc);
		}
			
	}
};

以下是叠甲:这个数据结构是我做题时突发奇想的,但我没有找到合适的题来试它,没有找到类似的动态插入查找问题,只能找到静态的题目来试试它的复杂程度对不对,根据洛谷p2422这个静态题目复杂程度大致是对的。

如果这个数据结构有名字或有差不多的,欢迎指正(看书可能少了)。

后面可能我会往平衡树,红黑树之类的方面看看继续优化一下,这个感觉还有空间,无用的操作还是多了。

提示:代码上为了适配试验的静态题目,用了预制的插入位+离散化来模拟;插入部分的代码大多是p1,p2两个轮换,结构都是差不多的(但是我懒得写封装函数优化了);注释我有时间会加上。

错误的地方欢迎指正,当然也欢迎点赞。

标签:p2,loc,cnt,p1,峰谷,yy,ff,序列,数据结构
From: https://blog.csdn.net/m0_62694887/article/details/145047690

相关文章

  • C++并发编程之基于锁的数据结构的适用场合与需要考虑和注意的问题
    在C++多线程编程中,锁是一种常用的同步机制,用于保护共享数据,防止多个线程同时访问和修改,从而避免数据不一致或其他并发问题。基于锁的数据结构适用于多种并发编程场合,但同时也需要注意一些关键问题。1. 适用的并发编程场合锁在以下几种场合特别有用:1.1 保护共享数据当多个......
  • C/C++ 数据结构与算法【排序】 常见7大排序详细解析【日常学习,考研必备】带图+详细代
    常见7种排序算法冒泡排序(BubbleSort)选择排序(SelectionSort)插入排序(InsertionSort)希尔排序(ShellSort)归并排序(MergeSort)快速排序(QuickSort)堆排序(HeapSort)计数排序(CountingSort)算法复杂度1、冒泡排序冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比......
  • 数据结构——单链表(C语言版:超详细)
    目录一、引言1.数据结构的重要性2.单链表在其中的地位二、什么是单链表1.单链表的定义2.基本概念解释三、单链表的结构特点1.与数组对比的优势2.存在的劣势四、单链表的基本操作1.节点的创建2.动态申请一个节点3.插入节点3.1尾插3.2头插3.3在pos之前插入3.4在......
  • 数据结构实验8
    7-2迪杰斯特拉方法实现最短路径用迪杰斯特拉算法实现有向网的最短路径输入格式:第一行输入有向网的顶点和边数,第二行输入各顶点值,用空格间隔,第三行开始输入各条边的两个点的及边上的权值,用空格间隔。最后一行输入要求路径的两个顶点。输出格式:输出最短路径经过的各顶点,中......
  • 数据结构实验9
    7-1整型关键字的散列映射给定一系列整型关键字和素数p,用除留余数法定义的散列函数H(key)=key%p将关键字映射到长度为p的散列表中。用线性探测法解决冲突。输入格式:输入第一行首先给出两个正整数n(≤1000)和p(≥n的最小素数),分别为待插入的关键字总数、以及散列表的长度。......
  • 数据结构实验10
    6-4快速排序本题要求实现快速排序的一趟划分函数,待排序列的长度1<=n<=1000。函数接口定义:intPartition(SqListL,intlow,inthigh);其中L是待排序表,使排序后的数据从小到大排列。类型定义:typedefintKeyType;typedefstruct{KeyTypeelem;/elem[0]一般作哨......
  • 数据结构实验1
    7-1线性表A,B顺序存储合并有两张非递增有序的线性表A,B,采用顺序存储结构,两张表合并用c表存,要求C为非递减有序的,然后删除C表中值相同的多余元素。元素类型为整型输入格式:第一行输入输入表A的各个元素,以-1结束,中间用空格分隔;第二行输入表B的各个元素,以-1结束,中间用空格分隔。输......
  • 数据结构实验二
    石家庄铁道大学实验报告课程名称:信2305-3 任课教师:刘丹 实验日期:2024.12.11班级:信2305-3 姓名:徐戌 学号:20234316实验项目名称:实验二一、 实验目的1.掌握栈的定义及......
  • 数据结构实验一
    石家庄铁道大学实验报告课程名称:数据结构与算法设计 任课教师:刘丹 实验日期:2024.12.11班级:信2305-3 姓名:徐戌 学号:20234316实验项目名称:实验一一、 实验目的掌握顺序表的......
  • 数据结构实验2
    7-2双向循环链表应用已知p指向双向循环链表中的一个结点,其结点结构为data、prior、next三个域,实现交换p所指向的结点和它的前缀结点的顺序。输入格式:第一行输入元素个数,第二行输入元素值,第三行输入要交换的元素值,第四行输出结果。输出格式:输出交换后的结果,中间不用空格分......