[ZJOI2007]报表统计

(提供一个通俗易懂的思路,绝对好懂

Description

给定 \(n\)\(m\) 和一个含有 \(n\) 个非负数的数组 \(a_1\ ,\ a_2\ ...\ a_{n-1}\ ,\ a_n\) 以及 \(m\) 个操作,操作含三种类型:

  1. \(\small INSERT\ \ i\ \ k\) :在原数组的第 \(i\) 个元素后面插入一个元素 \(k\) ,此后面指插入到之前所有插入第 \(i\) 个元素的元素的后面。

  2. \(\small MIN\_GAP\) :查询数组中相邻两个元素的之间差值的绝对值的最小值。

  3. \(\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;
}

只求能帮助到几个人罢。。

posted @ 2021-07-06 19:57  Illusory_dimes  阅读(71)  评论(0编辑  收藏  举报