BZOJ1058 ZJOI2007 报表统计 线段树+平衡树
题意:给定一个序列,维护:1、插入一个元素 2、求相邻两个元素中,差值绝对值的最小值 3、求序列排序后相邻两个元素中,差值绝对值的最小值
题解:
MIN_GAP:如果我们把数看成一组一组,每次插入数字都在一组的最后插入,那么答案只有可能在组内和组间两个位置产生,定义l[i]为一组数中最左边的数,r[i]为一组数中最右边的数,新插入的数为x,那么用|x-l[i]|取min来更新组内的最小值,|x-r[i]|强制更新组间的值。因此我们需要能单点修改,区间查询的数据结构,线段树走起。
MIN_SORT_GAP:由于答案与数的位置无关,Splay走起。显然与新插入的数x差值最小的数一定在插入过程走过的路经上(原因请自行脑补),开个ans维护答案即可。
这玩意比树套树啥的敲起来舒服多了
#include <cstdio> #include <cstring> #include <cstdlib> #include <climits> #include <iostream> #include <algorithm> using namespace std; const int MAXN=500000+2; int N,Q,ans=INT_MAX,l[MAXN],r[MAXN]; char S[20+2]; //Segment Tree begin typedef struct ST_NODE{ int l,r,m; ST_NODE *lchild,*rchild; ST_NODE(){} ST_NODE(int _l,int _r):l(_l),r(_r),m(INT_MAX),lchild(0),rchild(0){} } *ST_TREE; ST_TREE ST_root; void ST_Pushup(ST_TREE &x){ x->m=min(x->lchild->m,x->rchild->m);} void ST_Build(ST_TREE &root,int l,int r){ root=new ST_NODE(l,r); if(l==r) return; int m=(l+r)>>1; if(l<=m) ST_Build(root->lchild,l,m); if(m<r) ST_Build(root->rchild,m+1,r); } void ST_Insert(ST_TREE &x,int p,int a,bool t){ if(x->l==x->r){ if(t) x->m=a; else x->m=min(x->m,a); return; } int m=(x->l+x->r)>>1; if(p<=m) ST_Insert(x->lchild,p,a,t); else ST_Insert(x->rchild,p,a,t); ST_Pushup(x); } //Segment Tree end //Splay Tree begin typedef struct Splay_NODE{ int v; Splay_NODE *child[2],*f; Splay_NODE(){} Splay_NODE(int _v,Splay_NODE *_f):v(_v),f(_f){} } *Splay_TREE; Splay_TREE Null,Splay_root; Splay_TREE NewNode(int v,Splay_TREE f){ Splay_TREE x=new Splay_NODE(v,f); x->child[0]=x->child[1]=Null; return x; } void Splay_Init(){ Null=NewNode(INT_MAX,0); Splay_root=NewNode(INT_MAX>>1,Null); } void Rotate(Splay_TREE &x,bool t){ Splay_TREE y=x->f; y->child[!t]=x->child[t],x->child[t]->f=y,x->f=y->f; if(y->f->child[0]==y) y->f->child[0]=x; else y->f->child[1]=x; y->f=x,x->child[t]=y; if(y==Splay_root) Splay_root=x; } void Splay(Splay_TREE &x,Splay_TREE &y){ while(x->f!=y) if(x->f->f==y) if(x->f->child[0]==x) Rotate(x,1); else Rotate(x,0); else if(x->f->f->child[0]==x->f) if(x->f->child[0]==x) Rotate(x->f,1),Rotate(x,1); else Rotate(x,0),Rotate(x,1); else if(x->f->child[0]==x) Rotate(x,1),Rotate(x,0); else Rotate(x->f,0),Rotate(x,0); } void Splay_Insert(Splay_TREE &x,int a){ Splay_TREE y=x,z; while(y!=Null){ ans=min(ans,abs(a-y->v)),z=y; if(y->v>=a) y=y->child[0]; else y=y->child[1]; } if(z->v>=a) y=z->child[0]=NewNode(a,z); else y=z->child[1]=NewNode(a,z); Splay(y,Null); } //Splay Tree begin int main(){ scanf("%d %d",&N,&Q); Splay_Init(),ST_Build(ST_root,1,2*N-1); for(int i=1;i<=N;i++){ scanf("%d",l+i),r[i]=l[i]; ST_Insert(ST_root,2*(i-1)+1,INT_MAX,0); if(i!=1) ST_Insert(ST_root,2*(i-1),abs(l[i-1]-l[i]),1); Splay_Insert(Splay_root,l[i]); } for(int i=1,x,y;i<=Q;i++){ scanf("%s",S); if(strstr(S,"INSERT")){ scanf("%d %d",&x,&y); ST_Insert(ST_root,2*(x-1)+1,abs(y-r[x]),0); if(x!=N) ST_Insert(ST_root,2*x,abs(y-l[x+1]),1); Splay_Insert(Splay_root,y); r[x]=y; } if(strstr(S,"MIN_GAP")) printf("%d\n",ST_root->m); if(strstr(S,"MIN_SORT_GAP")) printf("%d\n",ans); } return 0; }