[ZJOI2007]报表统计
(提供一个通俗易懂的思路,绝对好懂
Description
给定 \(n\) , \(m\) 和一个含有 \(n\) 个非负数的数组 \(a_1\ ,\ a_2\ ...\ a_{n-1}\ ,\ a_n\) 以及 \(m\) 个操作,操作含三种类型:
-
\(\small INSERT\ \ i\ \ k\) :在原数组的第 \(i\) 个元素后面插入一个元素 \(k\) ,此后面指插入到之前所有插入第 \(i\) 个元素的元素的后面。
-
\(\small MIN\_GAP\) :查询数组中相邻两个元素的之间差值的绝对值的最小值。
-
\(\small MIN\_SORT\_GAP\) :查询数组中所有元素的之间差值的绝对值的最小值。
Prepose
平衡树(能懂,有板子就行)
小根堆(知道就行)
我是用的 \(splay\) ,感觉更好理解
Solution
第三个条件明显可以平衡树乱搞
第二个条件的话,需要一个能排序,能插入,能删除任意位置的数的东西。
想到的就是可删除的优先队列。(主要早上才讲)
不对,优先队列怎么删除任意位置???
自己写不就好了嘛!
typedef struct mdzz{
priority_queue<int ,vector<int> ,greater<int> > Q,D;
inline void push(int x){Q.push(x);}
inline void delt(int x){D.push(x);}//the quintessence
inline int top(){
while(!D.empty()&&Q.top()==D.top()){Q.pop();D.pop();}
return Q.empty()?-1:Q.top();
}
}DEL_SRH;
//easy to understand!
多好。。
想一想,好像第三个也可以一股脑全部搞进去
第一个条件那个占最多篇幅的条件,一个小数组 \(it\) 就可以解决
只是插入数时对两个 \(\small DEL\_SRH\) 修改时注意一些边界(比如加入的数在数组的最后一个)
看代码就能懂(长度中等)
思路特别通俗易懂,还学会了一个新的数据结构。。
并且即便是 \(splay\) 也跑的挺快,在最优解第一页尾巴那
Code
#include<bits/stdc++.h>
#define ls(i) spl[i].ch[0]
#define rs(i) spl[i].ch[1]
#define reg register
using namespace std;
typedef long long ll;
typedef struct mdzz{
priority_queue<int ,vector<int> ,greater<int> > Q,D;
inline void push(int x){Q.push(x);}
inline void delt(int x){D.push(x);}
inline int top(){
while(!D.empty()&&Q.top()==D.top()){Q.pop();D.pop();}
return Q.empty()?-1:Q.top();
}
}DEL_SRH;
const int N=1e6+10;
const int INF=16e8;
int n,m,root,tot,a[N],it[N],by[N];
DEL_SRH gap,sgap;
char opt[16];
struct Splay{int ch[2],fa,cnt,val,siz;}spl[N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
inline void pushup(int now){
spl[now].siz=spl[now].cnt+spl[ls(now)].siz+spl[rs(now)].siz;
}
inline void rotate(int now){
int nxt=spl[now].fa;
int nnt=spl[nxt].fa;
int k1=rs(nxt)==now;
int k2=rs(nnt)==nxt;
int pre=spl[now].ch[k1^1];
spl[nnt].ch[k2]=now; spl[now].fa=nnt;
spl[nxt].ch[k1]=pre; spl[pre].fa=nxt;
spl[now].ch[k1^1]=nxt; spl[nxt].fa=now;
pushup(nxt);pushup(now);
}//虽然肯定会跑得慢,但真tm好看
inline void splay(int now,int S){
while(spl[now].fa!=S){
int nxt=spl[now].fa;
int nnt=spl[nxt].fa;
int k1=rs(nxt)==now;
int k2=rs(nnt)==nxt;
if(nnt!=S)(k1^k2)?rotate(now):rotate(nxt);
rotate(now);
}
if(!S)root=now;
}
inline void insert(int now){
int u=root,fth=0;
while(u&&spl[u].val!=now){
fth=u;
u=spl[u].ch[now>spl[u].val];
}
if(u)++spl[u].cnt;
else {
u=++tot;ls(u)=rs(u)=0;
if(fth)spl[fth].ch[now>spl[fth].val]=u;
spl[u].cnt=spl[u].siz=1;
spl[u].fa=fth;spl[u].val=now;
}
splay(u,0);
}
inline void find(int now){
int u=root;
if(!u)return ;
while(spl[u].ch[now>spl[u].val]&&now!=spl[u].val)
u=spl[u].ch[now>spl[u].val];
splay(u,0);
}
inline int pre_nxt(int now,int k){
find(now);
int u=root;
if(spl[u].val<=now&&(!k))return spl[u].val;
if(spl[u].val>=now&&k)return spl[u].val;
u=spl[u].ch[k];
while(spl[u].ch[k^1])u=spl[u].ch[k^1];
return spl[u].val;
}
int main(){
insert(-INF);insert(INF);
n=read();m=read();
for(int i=1;i<=n;++i){
it[i]=a[i]=by[i]=read();
insert(a[i]);
if(i!=1)gap.push(abs(a[i]-a[i-1]));
}
sort(by+1,by+1+n);
for(int i=1;i<n;++i){
sgap.push(by[i+1]-by[i]);
}//这一段好沙雕
while(m--){
scanf("%s",opt);
if(opt[0]=='I'){
int id=read(),ai=read();
if(id!=n)gap.push(abs(ai-a[id+1]));
gap.push(abs(it[id]-ai));
gap.delt(abs(it[id]-a[id+1]));
it[id]=ai;
int pi=pre_nxt(ai,0),ni=pre_nxt(ai,1);
if(pi==-INF){
sgap.push(ni-ai);
}
else if(ni==INF){
sgap.push(ai-pi);
}
else {
sgap.delt(ni-pi);
sgap.push(ai-pi);
sgap.push(ni-ai);
}
insert(ai);
}
else if(opt[4]=='G'){
printf("%d\n",gap.top());
}
else if(opt[4]=='S'){
printf("%d\n",sgap.top());
}
}
return 0;
}
只求能帮助到几个人罢。。