【洛谷P1110】报表统计【平衡树】【堆】

题目大意:

题目链接:https://www.luogu.org/problem/P1110

在最开始的时候,有一个长度为NN的整数序列,并且有以下三种操作:

  • INSERT i kINSERT\ i\ k:在原数列的第ii个元素后面添加一个新元素kk;如果原数列的第ii个元素已经添加了若干元素,则添加在这些元素的最后
  • MIN_GAPMIN\_GAP:查询相邻两个元素的之间差值(绝对值)的最小值
  • MIN_SORT_GAPMIN\_SORT\_GAP:查询所有元素中最接近的两个元素的差值(绝对值)

思路:

首先操作三是很简单的,我们只要写一棵平衡树,维护每一个数字的前驱后继,每次插入一个数就判断它与它前驱后继的差值是否小于minnminn。如果小于就更新。
对于第二问,定义last[i]last[i]表示原序列第ii个数字后面插入的最后一个数字,如果我们在原序列第ii个数字后面插入xx,那么会受影响的只有abs(a[i+1]last[i])abs(a[i+1]-last[i])。因为在last[i]last[i]a[i+1]a[i+1]中插入了一个新的数字。
同时我们还加入了两个新的数字abs(xlast[i])abs(x-last[i])abs(xa[i+1])abs(x-a[i+1])。而我们要求这些数字的最小值,所以我们可以将所有这些数字插入一个小跟堆中。每次去最小值。
那么如果最小值本来应该删除的话怎么办呢?我们可以再建一个小根堆,把要删除的数字插入小根堆中。如果此时的最小值和要删除数字的最小值一样,那么这个最小值就是要删除的,两个堆都弹出即可。
时间复杂度O(mlog(n+m))O(m\log (n+m))


代码:

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=1000010,Inf=1e9;
int n,m,root,minn,a[N],last[N];
char ch[30];
priority_queue<int> q,p;

struct Treenode
{
	int lc,rc,val,cnt,dat;
};

struct Treap
{
	Treenode tree[N];
	int tot;
	
	int New(int val)
	{
		tree[++tot].val=val;
		tree[tot].dat=rand();
		tree[tot].cnt=1;
		return tot;
	}
	
	void build()
	{
		root=New(-Inf);
		tree[root].rc=New(Inf);
	}
	
	void zig(int &x)
	{
		int y=tree[x].lc;
		tree[x].lc=tree[y].rc; tree[y].rc=x; x=y;
	}
	
	void zag(int &x)
	{
		int y=tree[x].rc;
		tree[x].rc=tree[y].lc; tree[y].lc=x; x=y;
	}
	
	void insert(int &x,int val)
	{
		if (!x)
		{
			x=New(val);
			return;
		}
		if (tree[x].val==val)
		{
			tree[x].cnt++;
			return;
		}
		if (val<tree[x].val)
		{
			insert(tree[x].lc,val);
			if (tree[x].dat<tree[tree[x].lc].dat) zig(x);
		}
		else
		{
			insert(tree[x].rc,val);
			if (tree[x].dat<tree[tree[x].rc].dat) zag(x);
		}
	}
	
	int pre(int x,int val)
	{
		if (!x) return -Inf;
		if (tree[x].val<val) return max(tree[x].val,pre(tree[x].rc,val));
			else return pre(tree[x].lc,val);
	}
	
	int next(int x,int val)
	{
		if (!x) return Inf;
		if (tree[x].val>val) return min(tree[x].val,next(tree[x].lc,val));
			else return next(tree[x].rc,val);
	}
	
	int cnt(int x,int val)
	{
		if (!x) return 0;
		if (val==tree[x].val) return tree[x].cnt;
		if (val<tree[x].val) return cnt(tree[x].lc,val);
			else return cnt(tree[x].rc,val);
	}
}Treap;

int main()
{
	srand(23333);
	Treap.build();
	scanf("%d%d",&n,&m);
	minn=Inf;
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		last[i]=a[i];
		Treap.insert(root,a[i]);
		if (i>1) q.push(-abs(a[i]-a[i-1]));
		if (Treap.cnt(root,a[i])>1) minn=0;
		if (minn)
		{
			int ans1=a[i]-Treap.pre(root,a[i]),ans2=Treap.next(root,a[i])-a[i];
			minn=min(minn,min(ans1,ans2));
		}
	}
	while (m--)
	{
		scanf("%s",ch+1);
		if (ch[1]=='I')
		{
			int x,y;
			scanf("%d%d",&x,&y);
			Treap.insert(root,y);
			q.push(-abs(y-last[x]));
			if (x<n)
			{
				q.push(-abs(y-a[x+1]));
				p.push(-abs(last[x]-a[x+1]));
			}
			if (Treap.cnt(root,y)>1) minn=0;
			if (minn)
			{
				int ans1=y-Treap.pre(root,y),ans2=Treap.next(root,y)-y;
				minn=min(minn,min(ans1,ans2));
			}
			last[x]=y;
		}
		else if (ch[5]=='S') printf("%d\n",minn);
		else
		{
			while (q.size() && p.size() && q.top()==p.top())
				q.pop(),p.pop();
			printf("%d\n",-q.top());
		}
	}
	return 0;
}
posted @ 2019-10-06 10:17  全OI最菜  阅读(132)  评论(0编辑  收藏  举报