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;
}
View Code

 

posted @ 2017-02-28 23:26  WDZRMPCBIT  阅读(...)  评论(... 编辑 收藏