zoukankan      html  css  js  c++  java
  • [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('
    ');
            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('
    ');
        }
        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('
    ');
                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('
    ');
            }else if(op[4]=='G') printf("%d
    ",A.gap[A.rt]);
            else printf("%d
    ",sort_gap);
        }
    }
    /*
    3 5
    5 3 1
    INSERT 2 9
    MIN_SORT_GAP
    INSERT 2 6
    MIN_GAP
    MIN_SORT_GAP
    */
    
  • 相关阅读:
    PHP 抽象类
    PHP使用rabbitmq发邮件简单使用
    自定义Chrome插件Vimium
    用Paint Tool SAI绘制漫画
    AutoHotkey 使用笔记
    Unity 性能
    VS2015解决非Unicode编码包含中文字段无法编译的问题
    高DPI设置时禁用显示的方法
    Excel 统计在某个区间内数值的个数
    自定义宏把Word打造成全快捷键编辑器
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/13882422.html
Copyright © 2011-2022 走看看