Luogu P1110 [ZJOI2007] 报表统计

题目描述

给定一个长度为 \(n\) 的整数序列 \(a\),有以下三种操作:

  • INSERT i x\(i\) 位置后面添加一个新元素 \(x\),下一个元素挂在这个元素后面。
  • MIN_GAP:查询相邻元素差值的最小值。
  • MIN_SORT_GAP:查询元素中最接近的两个元素的差值。

题目解析

平衡树经典题目。建立 \(2\) 棵平衡树,分别维护所谓的相邻元素差值与最接近的差值,也就是 MIN_GAPMIN_SORT_GAP

对于 Insert 和 Delete 操作;

  • MIN_GAP 平衡树维护的是相邻差值。先将原本的所有相邻元素之间的差值 Insert 进平衡树,再记录一个 \(lst_i\) 表示以 \(a_i\) 为开头的添加于 \(i\) 后的上一个元素。对于一个 \(1 \le i \le n\),每一次 INSERT i x 操作,上一次的 \(lst_i\)\(a_{i+1}\) 之间的相邻关系消除,即 Delete 掉 \(|lst_i-a_{i+1}|\);本次增加 \(lst_i\)\(x\) 之间的相邻关系,以及 \(x\)\(a_{i+1}\) 之间的相邻关系,即 Insert 进 \(|lst_i-x|\)\(|x-a_{i+1}|\)

  • MIN_SORT_GAP 平衡树维护的是最接近的两个元素的差值?其实也不然。先将 \(a\) 数组的所有元素 Insert 进去,每次 INSERT i x 操作也就是 Insert 进去 \(x\)。只是每个元素在 Insert 进去前先用当前他与 pre 和 nxt 之间的差值更新一下答案而已,运用平衡树,这就相当于去求排序后所有相邻元素之间的差值的最小值。

最终对于 MIN_GAP 的询问,输出 rk 为 \(1\) 的元素即可;对于 MIN_SORT_GAP 的询问,输出记录最小值的变量即可。

实现写的是 FHQ-Treap,FHQ-Treap 太好写辣(

代码实现

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,q,ans=INT_MAX;
int a[1145141],b[1145141],lsta[1145141],lstb[1145141];
int rt1,rt2,l1=0,r1=0,l2=0,r2=0,px1,px2,cnt1=0,cnt2=0;
struct node{
	int l,r,siz,val,randval;
}Treap1[1145141],Treap2[1145141];
void pushup1(int p){
	Treap1[p].siz=Treap1[Treap1[p].l].siz+Treap1[Treap1[p].r].siz+1;
	return ;
}
void build1(int x){
	++cnt1;
	Treap1[cnt1].l=Treap1[cnt1].r=0;
	Treap1[cnt1].siz=1;
	Treap1[cnt1].val=x;
	Treap1[cnt1].randval=rand();
	return ;
}
void Split1(int p,int val,int &l,int &r){
	if(!p){
		l=r=0;
		return ;
	}
	if(Treap1[p].val<=val){ 
		l=p; 
		Split1(Treap1[p].r,val,Treap1[p].r,r); 
	}else{
		r=p; 
		Split1(Treap1[p].l,val,l,Treap1[p].l); 
	}
	pushup1(p);
	return ;
}

int Merge1(int l,int r){
	if(!l||!r) return l+r;
	if(Treap1[l].randval<=Treap1[r].randval){
		Treap1[l].r=Merge1(Treap1[l].r,r);
		pushup1(l);
		return l;
	}
	Treap1[r].l=Merge1(l,Treap1[r].l);
	pushup1(r);
	return r;
}

void Insert1(int x){
	Split1(rt1,x,l1,r1);
	build1(x);
	rt1=Merge1(Merge1(l1,cnt1),r1);
	return ;
}

void Delete1(int x){
	Split1(rt1,x,l1,r1);
	Split1(l1,x-1,l1,px1);
	px1=Merge1(Treap1[px1].l,Treap1[px1].r);
	rt1=Merge1(Merge1(l1,px1),r1);
	return ;
}

int rk1(int p,int k){
	if(k==Treap1[Treap1[p].l].siz+1) return p;
	if(k<Treap1[Treap1[p].l].siz+1) return rk1(Treap1[p].l,k);
	k-=Treap1[Treap1[p].l].siz+1;
	return rk1(Treap1[p].r,k);
}
void pushup2(int p){
	Treap2[p].siz=Treap2[Treap2[p].l].siz+Treap2[Treap2[p].r].siz+1;
	return ;
}
void build2(int x){
	++cnt2;
	Treap2[cnt2].l=Treap2[cnt2].r=0;
	Treap2[cnt2].siz=1;
	Treap2[cnt2].val=x;
	Treap2[cnt2].randval=rand();
	return ;
}
void Split2(int p,int val,int &l,int &r){
	if(!p){
		l=r=0;
		return ;
	}
	if(Treap2[p].val<=val){ 
		l=p; 
		Split2(Treap2[p].r,val,Treap2[p].r,r); 
	}else{
		r=p; 
		Split2(Treap2[p].l,val,l,Treap2[p].l); 
	}
	pushup2(p);
	return ;
}

int Merge2(int l,int r){
	if(!l||!r) return l+r;
	if(Treap2[l].randval<=Treap2[r].randval){
		Treap2[l].r=Merge2(Treap2[l].r,r);
		pushup2(l);
		return l;
	}
	Treap2[r].l=Merge2(l,Treap2[r].l);
	pushup2(r);
	return r;
}

void Insert2(int x){
	Split2(rt2,x,l2,r2);
    if(Treap2[l2].siz){
        int now=l2;
        while(Treap2[now].r) now=Treap2[now].r;
        ans=min(ans,abs(x-Treap2[now].val));
    }
    if(Treap2[r2].siz){
        int now=r2;
        while(Treap2[now].l) now=Treap2[now].l;
        ans=min(ans,abs(Treap2[now].val-x));
    }
	build2(x);
	rt2=Merge2(Merge2(l2,cnt2),r2);
	return ;
}

void Delete2(int x){
	Split2(rt2,x,l2,r2);
	Split2(l2,x-1,l2,px2);
	px2=Merge2(Treap2[px2].l,Treap2[px2].r);
	rt2=Merge2(Merge2(l2,px2),r2);
	return ;
}

signed main(){
	cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) b[i]=a[i];
	sort(b+1,b+n+1);
	for(int i=1;i<n;i++) Insert1(abs(a[i+1]-a[i]));
	for(int i=1;i<n;i++) Insert2(a[i]);
	for(int i=1;i<=n;i++) lsta[i]=a[i];
	while(q--){
		string op;
		cin>>op;
		if(op=="INSERT"){
			int ii,x;
			cin>>ii>>x;
            Insert2(x);
			if(ii==n){
				Delete1(abs(a[n]-lsta[n]));
				Insert1(abs(x-lsta[n]));
				lsta[n]=x; 
			}
			else{
				Delete1(abs(a[ii+1]-lsta[ii]));
				Insert1(abs(x-lsta[ii]));
				Insert1(abs(a[ii+1]-x));
				lsta[ii]=x;
			}
		}
		else if(op=="MIN_GAP") cout<<Treap1[rk1(rt1,1)].val<<endl;
		else cout<<ans<<endl;
	}
	return 0;
}

posted @ 2024-07-04 11:38  HAM_qwq  阅读(19)  评论(0编辑  收藏  举报