[ZJOI2007]报表统计

题目描述

  1. 原数列\(i\) 个后面添加一个新元素 \(k\);如果原数列的第 \(i\) 个元素已经添加了若干元素,则添加在这些元素的最后。
  2. 查询相邻两个元素的差值的绝对值的最小值。
  3. 查询所有元素中一对元素的差值的绝对值的最小值。

解法

第一个操作很好维护,若要在第 \(i\) 个元素后面插值,那么实际需要插入的位置是 \(i+s_i+1\) ,其中 \(s_i\) 表示原数列第 \(i\) 个数及以前的数后面一共插了多少个数。若 \(s_i\) 加一,那么 \(s_{i+1}~s_n\) 都会加一,显然可以用树状数组做。

第三个操作也好维护,建一棵以值为关键字的平衡树即可。每次插入新元素时,查询前驱后继,更新答案。

关键在于第二个操作,一开始我想的和第三个操作一样,再建一棵以位置为关键字的平衡树,查前驱后继更新答案。但这显然是不对的,因为当一个数 \(a\) 插入到 \(b\)\(c\) 中间时,\(b\) 的后继和 \(c\) 的前驱会变,而之前的答案很可能是 \(|b-c|\)。我们换个思路,考虑多维护一些值 \(pre\)\(nex\)\(gap\) 分别表示一个数和前驱的差值、和后继的差值、整棵子树中 \(pre\)\(nex\) 的最小值的最小值。当一个数被插入时,有且仅有 \(3\) 个数的前驱和后继发生变化,而对于每个更改,只会修改一条链,所以我们记录一个 \(fa\) ,每次更新完一个节点后都从当前节点跳 \(fa\)\(update\)。最后的答案就是 \(gap[root]\)

inline void update(int id){
    sz[id]=1;
    gap[id]=min(pre[id],nex[id]);
    if(lid) sz[id]+=sz[lid],gap[id]=min(gap[id],gap[lid]),fa[lid]=id;
    if(rid) sz[id]+=sz[rid],gap[id]=min(gap[id],gap[rid]),fa[rid]=id;
}

Tips

若平衡树为空,查前驱后继的时候可能会出问题,\(gap\) 的值也可能出问题,故预先插入一个 \(-inf\)\(inf\)

两颗平衡树可以用 \(struct\) 分开写,这样思路清晰不容易挂。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 1000007
#define lid s[id][0]
#define rid s[id][1]
#define INF (1<<30)

int n,m;

inline int read(){
    int x=0; bool tag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')tag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return tag? x:-x;
}

inline int abs(int x){return x<0? -x:x;}
inline int min(int x,int y){return x<y? x:y;}

struct BIT{
    int c[N];
    inline int lowbit(int x){return x&(-x);}
    inline void add(int x){while(x<=n)c[x]++,x+=lowbit(x);}
    inline int query(int x){int ret=0;while(x)ret+=c[x],x-=lowbit(x);return ret;}
}T;

struct FHQ_Pos{
    int rt,key[N],s[N][2],val[N],sz[N],cnt,pre[N],nex[N],gap[N],fa[N];
    
    FHQ_Pos(){rt=cnt=0;}
    
    inline void update(int id){
        sz[id]=1;
        gap[id]=min(pre[id],nex[id]);
        if(lid) sz[id]+=sz[lid],gap[id]=min(gap[id],gap[lid]),fa[lid]=id;
        if(rid) sz[id]+=sz[rid],gap[id]=min(gap[id],gap[rid]),fa[rid]=id;
    }
    
    inline int New(int x){
        key[++cnt]=rand();
        val[cnt]=x;
        s[cnt][0]=s[cnt][1]=0;
        sz[cnt]=1;
        pre[cnt]=nex[cnt]=gap[cnt]=INF;
        fa[cnt]=0;
        return cnt;
    }
    
    int merge(int x,int y){
        if(!x||!y) return x+y;
        if(key[x]<key[y]){
            s[x][1]=merge(s[x][1],y);
            update(x);
            return x;
        }else{
            s[y][0]=merge(x,s[y][0]);
            update(y);
            return y;
        }
    }
    
    void split(int id,int k,int &x,int &y){
        if(!id) x=y=0;
        else{
            if(sz[lid]<k) x=id,split(rid,k-sz[lid]-1,rid,y);
            else y=id,split(lid,k,x,lid);
            update(id);
        }
    }
    
    int kth(int id,int k){
        while(1){
            if(sz[lid]>=k) id=lid;
            else if(sz[lid]+1==k) return id;
            else k-=sz[lid]+1,id=rid;
        }
    }
    
    void print(int id){
        if(lid) print(lid);
        printf("%d ",val[id]);
        if(rid) print(rid);
    }
    
}A;

struct FHQ_Val{
    int rt,key[N],s[N][2],val[N],sz[N],cnt;
    
    FHQ_Val(){rt=cnt=0;}
    
    inline void update(int id){sz[id]=sz[lid]+sz[rid]+1;}
    
    inline int New(int x){
        key[++cnt]=rand();
        val[cnt]=x;
        s[cnt][0]=s[cnt][1]=0;
        sz[cnt]=1;
        return cnt;
    }
    
    int merge(int x,int y){
        if(!x||!y) return x+y;
        if(key[x]<key[y]){
            s[x][1]=merge(s[x][1],y);
            update(x);
            return x;
        }else{
            s[y][0]=merge(x,s[y][0]);
            update(y);
            return y;
        }
    }
    
    void split(int id,int k,int &x,int &y){
        if(!id) x=y=0;
        else{
            if(val[id]<=k) x=id,split(rid,k,rid,y);
            else y=id,split(lid,k,x,lid);
            update(id);
        }
    }
    
    int kth(int id,int k){
        while(1){
            if(sz[lid]>=k) id=lid;
            else if(sz[lid]+1==k) return id;
            else k-=sz[lid]+1,id=rid;
        }
    }
    
    void print(int id){
        if(lid) print(lid);
        printf("%d ",val[id]);
        if(rid) print(rid);
    }
    
}B;

int sort_gap=INF;
inline void update(int id){
    int now=id;
    while(now) A.update(now),now=A.fa[now];
}

int main(){
//    freopen("data.in","r",stdin);
//    freopen("mine.out","w",stdout);
    srand(time(NULL));
    n=read(),m=read();
    A.rt=A.New(-INF);
    B.rt=B.merge(B.New(-INF),B.New(INF));
    int x,y,z,w;
    for(int i=1;i<=n;i++){
        int v=read();
        int t=A.New(v);
        T.add(i);
        int val=abs(A.val[A.cnt-1]-v);
        A.nex[A.cnt-1]=A.pre[t]=val;
        update(A.cnt-1);
        A.rt=A.merge(A.rt,t);
//        printf("A: ");
//        A.print(A.rt);
//        putchar('\n');
        B.split(B.rt,v,x,y);
        int pr=B.val[B.kth(x,B.sz[x])];
        int ne=B.val[B.kth(y,1)];
        sort_gap=min(sort_gap,abs(v-pr));
        sort_gap=min(sort_gap,abs(v-ne));
        B.rt=B.merge(B.merge(x,B.New(v)),y);
//        printf("B: ");
//        B.print(B.rt);
//        putchar('\n');
    }
    A.rt=A.merge(A.rt,A.New(INF));
    char op[10]={0};
    for(int i=1;i<=m;i++){
        scanf("%s",op);
        if(op[0]=='I'){
            int pos=read(),v=read();
            int t=A.New(v);
            T.add(pos);
            pos=T.query(pos);
            A.split(A.rt,pos,x,y);
            int pre=A.kth(x,A.sz[x]);
            A.nex[pre]=A.pre[t]=abs(A.val[pre]-v);
            update(pre);
            int nex=A.kth(y,1);
            A.pre[nex]=A.nex[t]=abs(A.val[nex]-v);
            update(nex);
            A.rt=A.merge(A.merge(x,t),y);
//            printf("A: ");
//            A.print(A.rt);
//            putchar('\n');
            B.split(B.rt,v,x,y);
            pre=B.val[B.kth(x,B.sz[x])];
            nex=B.val[B.kth(y,1)];
            sort_gap=min(sort_gap,abs(v-pre));
            sort_gap=min(sort_gap,abs(v-nex));
            B.rt=B.merge(B.merge(x,B.New(v)),y);
//            printf("B: ");
//            B.print(B.rt);
//            putchar('\n');
        }else if(op[4]=='G') printf("%d\n",A.gap[A.rt]);
        else printf("%d\n",sort_gap);
    }
}
/*
3 5
5 3 1
INSERT 2 9
MIN_SORT_GAP
INSERT 2 6
MIN_GAP
MIN_SORT_GAP
*/
posted @ 2020-10-27 07:49  Kreap  阅读(83)  评论(0编辑  收藏  举报