题目大意:
题目链接:https://www.luogu.org/problem/P1110
在最开始的时候,有一个长度为 N N N的整数序列,并且有以下三种操作:
- I N S E R T i k INSERT\ i\ k INSERT i k:在原数列的第 i i i个元素后面添加一个新元素 k k k;如果原数列的第 i i i个元素已经添加了若干元素,则添加在这些元素的最后
- M I N _ G A P MIN\_GAP MIN_GAP:查询相邻两个元素的之间差值(绝对值)的最小值
- M I N _ S O R T _ G A P MIN\_SORT\_GAP MIN_SORT_GAP:查询所有元素中最接近的两个元素的差值(绝对值)
思路:
首先操作三是很简单的,我们只要写一棵平衡树,维护每一个数字的前驱后继,每次插入一个数就判断它与它前驱后继的差值是否小于
m
i
n
n
minn
minn。如果小于就更新。
对于第二问,定义
l
a
s
t
[
i
]
last[i]
last[i]表示原序列第
i
i
i个数字后面插入的最后一个数字,如果我们在原序列第
i
i
i个数字后面插入
x
x
x,那么会受影响的只有
a
b
s
(
a
[
i
+
1
]
−
l
a
s
t
[
i
]
)
abs(a[i+1]-last[i])
abs(a[i+1]−last[i])。因为在
l
a
s
t
[
i
]
last[i]
last[i]和
a
[
i
+
1
]
a[i+1]
a[i+1]中插入了一个新的数字。
同时我们还加入了两个新的数字
a
b
s
(
x
−
l
a
s
t
[
i
]
)
abs(x-last[i])
abs(x−last[i])和
a
b
s
(
x
−
a
[
i
+
1
]
)
abs(x-a[i+1])
abs(x−a[i+1])。而我们要求这些数字的最小值,所以我们可以将所有这些数字插入一个小跟堆中。每次去最小值。
那么如果最小值本来应该删除的话怎么办呢?我们可以再建一个小根堆,把要删除的数字插入小根堆中。如果此时的最小值和要删除数字的最小值一样,那么这个最小值就是要删除的,两个堆都弹出即可。
时间复杂度
O
(
m
log
(
n
+
m
)
)
O(m\log (n+m))
O(mlog(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;
}