P1110 [ZJOI2007] 报表统计
P1110 [ZJOI2007] 报表统计
题目描述
小 Q 的妈妈是一个出纳,经常需要做一些统计报表的工作。今天是妈妈的生日,小 Q 希望可以帮妈妈分担一些工作,作为她的生日礼物之一。
经过仔细观察,小 Q 发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作。
在最开始的时候,有一个长度为
INSERT i k
:在原数列的第 个元素后面添加一个新元素 ;如果原数列的第 个元素已经添加了若干元素,则添加在这些元素的最后(见样例说明)。MIN_GAP
:查询相邻两个元素的之间差值(绝对值)的最小值。MIN_SORT_GAP
:查询所有元素中最接近的两个元素的差值(绝对值)。
于是小 Q 写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?
数据规模与约定
对于全部的测试点,保证
说句闲话
又是一道在压在List里很久的题 (然后你就一直拖到现在才写是吧)
Solution:
不难发现,INSERT i k
简直是平衡树模板, MIN_SORT_GAP
显然是单调不升的一个东西,我们只需要在 INSERT i k
时维护一下 MIN_GAP
。
所以我们再维护两个值,
一些细节:
由于我们的
Code:
#include<bits/stdc++.h> const int N=1.1e6+5; const int inf=1e9; using namespace std; int n,m,flag; int rd(){return rand()*rand()+17;} struct FHQ_Treap{ int cnt=0,rt; struct Tree{ int ls,rs,val,siz,pre,suf,ans,pri; }t[N]; int Node(int val){t[++cnt]={0,0,val,1,val,val,inf,rd()};return cnt;} inline void pushup(int x) { int ls=t[x].ls,rs=t[x].rs; t[x].siz=t[ls].siz+t[rs].siz+1; t[x].suf=t[x].pre=t[x].val; if(ls)t[x].pre=t[ls].pre; if(rs)t[x].suf=t[rs].suf; t[x].ans=inf; if(ls)t[x].ans=min({abs(t[ls].suf-t[x].val),t[ls].ans,t[x].ans}); if(rs)t[x].ans=min({abs(t[rs].pre-t[x].val),t[rs].ans,t[x].ans}); } void splite_siz(int x,int &a,int &b,int k) { if(!x){a=b=0;return ;} int tmp=t[t[x].ls].siz+1; if(k>=tmp){a=x;splite_siz(t[x].rs,t[x].rs,b,k-tmp);} else {b=x;splite_siz(t[x].ls,a,t[x].ls,k);} pushup(x); } void splite_val(int x,int &a,int &b,int k) { if(!x){a=b=0;return ;} if(k>=t[x].val){a=x;splite_val(t[x].rs,t[x].rs,b,k);} else {b=x;splite_val(t[x].ls,a,t[x].ls,k);} pushup(x); } int merge(int x,int y) { if(!x||!y)return x|y; if(t[x].pri<t[y].pri){t[x].rs=merge(t[x].rs,y);pushup(x);return x;} else {t[y].ls=merge(x,t[y].ls);pushup(y);return y;} } }T1,T2; struct Segment_Tree{ #define ls x<<1 #define rs x<<1|1 struct Tree{ int cnt; }t[N]; void build(int x,int l,int r) { t[x].cnt=r-l+1; if(l==r)return; int mid=l+r>>1; build(ls,l,mid);build(rs,mid+1,r); } void upd(int x,int l,int r,int pos) { t[x].cnt++; if(l==r)return; int mid=l+r>>1; if(pos<=mid)upd(ls,l,mid,pos); if(mid<pos)upd(rs,mid+1,r,pos); } int query(int x,int l,int r,int L,int R) { if(L<=l&&r<=R)return t[x].cnt; int mid=l+r>>1,res=0; if(L<=mid)res+=query(ls,l,mid,L,R); if(mid<R)res+=query(rs,mid+1,r,L,R); return res; } #undef ls #undef rs }T; int ans[2]={inf,inf}; void check(int x) { int a,b,c; T1.splite_siz(T1.rt,a,b,x); T1.splite_siz(b,b,c,1); cout<<T1.t[b].val<<"\n"; T1.rt=T1.merge(T1.merge(a,b),c); } void debug() { for(int i=0;i<T1.cnt;i++)check(i); cout<<"\n"; } void insert(int pos,int val) { int a,b,c,d; a=b=c=d=0; T1.splite_siz(T1.rt,a,c,pos); T1.rt=T1.merge(T1.merge(a,T1.Node(val)),c); ans[0]=T1.t[T1.rt].ans; a=b=c=d=0; T2.splite_val(T2.rt,a,c,val); T2.splite_siz(a,a,b,T2.t[a].siz-1); T2.splite_siz(c,c,d,1); if(b)ans[1]=min(ans[1],abs(T2.t[b].val-val)); if(c)ans[1]=min(ans[1],abs(T2.t[c].val-val)); T2.rt=T2.merge(T2.merge(T2.merge(a,b),T2.Node(val)),T2.merge(c,d)); } char c[20]; void work() { cin>>n>>m; for(int i=1,x;i<=n;i++) { scanf("%d",&x); insert(i-1,x); } T.build(1,1,n); for(int i=1,pos,val,tot;i<=m;i++) { scanf("%s",c); if(c[0]=='I') { scanf("%d%d",&pos,&val); tot=T.query(1,1,n,1,pos); insert(tot,val); T.upd(1,1,n,pos); } if(c[4]=='G') { printf("%d\n",T1.t[T1.rt].ans); } if(c[4]=='S') { printf("%d\n",ans[1]); } } } int main() { //freopen("P1110_1.in","r",stdin);freopen("P1110.out","w",stdout); work(); return 0; }