【洛谷P1110】报表统计【平衡树】【堆】
题目大意:
题目链接:https://www.luogu.org/problem/P1110
在最开始的时候,有一个长度为的整数序列,并且有以下三种操作:
- :在原数列的第个元素后面添加一个新元素;如果原数列的第个元素已经添加了若干元素,则添加在这些元素的最后
- :查询相邻两个元素的之间差值(绝对值)的最小值
- :查询所有元素中最接近的两个元素的差值(绝对值)
思路:
首先操作三是很简单的,我们只要写一棵平衡树,维护每一个数字的前驱后继,每次插入一个数就判断它与它前驱后继的差值是否小于。如果小于就更新。
对于第二问,定义表示原序列第个数字后面插入的最后一个数字,如果我们在原序列第个数字后面插入,那么会受影响的只有。因为在和中插入了一个新的数字。
同时我们还加入了两个新的数字和。而我们要求这些数字的最小值,所以我们可以将所有这些数字插入一个小跟堆中。每次去最小值。
那么如果最小值本来应该删除的话怎么办呢?我们可以再建一个小根堆,把要删除的数字插入小根堆中。如果此时的最小值和要删除数字的最小值一样,那么这个最小值就是要删除的,两个堆都弹出即可。
时间复杂度
代码:
#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;
}