zoukankan      html  css  js  c++  java
  • luoguP1110 [ZJOI2007]报表统计 [Splay]

    题目描述

    小 Q 的妈妈是一个出纳,经常需要做一些统计报表的工作。今天是妈妈的生日,小 Q 希望可以帮妈妈分担一些工作,作为她的生日礼物之一。

    经过仔细观察,小 Q 发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作。

    在最开始的时候,有一个长度为 nn 的整数序列 aa,并且有以下三种操作:

    • INSERT i k:在原数列的第 ii 个元素后面添加一个新元素 kk;如果原数列的第 ii 个元素已经添加了若干元素,则添加在这些元素的最后(见样例说明)。
    • MIN_GAP:查询相邻两个元素的之间差值(绝对值)的最小值。
    • MIN_SORT_GAP:查询所有元素中最接近的两个元素的差值(绝对值)。

    于是小 Q 写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?

    输入格式

    第一行包含两个整数,分别表示原数列的长度 nn 以及操作的次数 mm。

    第二行为 nn 个整数,为初始序列,第 ii 个整数表示 a_iai

    接下来的 mm 行,每行一个操作,即INSERT i kMIN_GAPMIN_SORT_GAP 中的一种(无多余空格或者空行)。

    输出格式

    对于每一个 MIN_GAP 和 MIN_SORT_GAP 命令,输出一行答案即可。

    输入输出样例

    输入 #1
    3 5
    5 3 1
    INSERT 2 9
    MIN_SORT_GAP
    INSERT 2 6
    MIN_GAP
    MIN_SORT_GAP
    
    输出 #1
    2
    2
    1
    

    说明/提示

    样例输入输出 1 解释

    一开始的序列为 {5,3,1}{5,3,1}。

    执行操作 INSERT 2 9 将得到 {5,3,9,1}{5,3,9,1},此时 MIN_GAP 为 22,MIN_SORT_GAP 为 22。

    再执行操作 INSERT 2 6 将得到:{5,3, 9, 6, 1}{5,3,9,6,1}。

    注意这个时候原序列的第 22 个元素后面已经添加了一个 99,此时添加的 66 应加在 99 的后面。这个时候 MIN_GAP 为 22,MIN_SORT_GAP 为 11。


    数据规模与约定

    对于全部的测试点,保证 2<=n,m<=5*10^5, 1<=i<=n, 0<=ai,k<=5*10^8

    Solution

    考虑每做完一次INSERT操作,将MIN_GAP和MIN_SORT_GAP的答案更新。

    考虑建立两个数据结构用以维护答案。

    1. 建立Splay树,节点值为相邻数的差(绝对值),当进行一次INSERT操作时,需要将被插入的两数的差的节点删掉,再分别加入新数与这两数的差(边界特殊考虑),答案ans1则为这棵树的最小节点,向左儿子寻找即可

    2. 建立另一棵Splay树,节点值为各节点的值,每一次插入新的值后根据其与前驱和后继更新答案ans2(注意初始化)

    终于复活了ovo!细节写挂,各种神奇过样例,这题贡献了我提交记录的一片红2333

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    using namespace std;
    #define inf 0x7f7f7f7f
    #define dbg(x) cout<<#x<<" = "<<x<<endl
    
    struct Splay{
        int v,num,ch[2],fa;
    };
    
    const int maxn=500005;
    
    int n,m,root[2],cnt[2],ans1,ans2=inf;
    int head[maxn],tail[maxn];
    
    Splay T[2][maxn*3];
    
    void rot(int flag,int x,int kind){
        int y=T[flag][x].fa,z=T[flag][y].fa;
        T[flag][y].ch[!kind]=T[flag][x].ch[kind];
        if(T[flag][x].ch[kind])  T[flag][T[flag][x].ch[kind]].fa=y;
        T[flag][x].fa=z;
        if(z)  T[flag][z].ch[y==T[flag][z].ch[1]]=x;
        T[flag][y].fa=x;  T[flag][x].ch[kind]=y;
    }
    
    void splay(int flag,int x){
        if(x==0)  return;
        while(T[flag][x].fa){
            int y=T[flag][x].fa,z=T[flag][y].fa;
            if(!z)  rot(flag,x,T[flag][y].ch[0]==x);
            else  if(T[flag][z].ch[0]==y){
                if(T[flag][y].ch[0]==x)  rot(flag,y,1),rot(flag,x,1);
                else  rot(flag,x,0),rot(flag,x,1);
            }
            else{
                if(T[flag][y].ch[1]==x)  rot(flag,y,0),rot(flag,x,0);
                else  rot(flag,x,1),rot(flag,x,0);
            }
        }
        root[flag]=x;
    }
    
    void inc(int flag,int x){
        int pos=root[flag],fa=0;
        while(pos&&T[flag][pos].v!=x){
            fa=pos;
            pos=T[flag][pos].ch[x>T[flag][pos].v];
        }
        if(pos)  T[flag][pos].num++;
        else{
            pos=++cnt[flag];
            T[flag][pos].v=x;
            T[flag][pos].fa=fa;
            T[flag][pos].num=1;
            T[flag][fa].ch[x>T[flag][fa].v]=pos;
        }
        splay(flag,pos);
    }
    
    void fin(int flag,int x){
        int pos=root[flag];
        while(1)
            if(x<T[flag][pos].v)
                pos=T[flag][pos].ch[0];
            else{
                if(x==T[flag][pos].v){
                    splay(flag,pos);
                    return;
                }
                pos=T[flag][pos].ch[1];
            }
    }
    
    int ne(int flag,int kind){
        int pos=T[flag][root[flag]].ch[kind];
        while(T[flag][pos].ch[!kind])  pos=T[flag][pos].ch[!kind];
        return pos;
    }
    
    void del(int flag,int x){
        fin(flag,x);
        int rt=root[flag];
        if(T[flag][rt].num>1){
            T[flag][rt].num--;
            return;
        }
        if(!T[flag][rt].ch[0]&&!T[flag][rt].ch[1]){
            rt=0;
            return;
        }
        if(!T[flag][rt].ch[0]){
            rt=T[flag][rt].ch[1];
            T[flag][rt].fa=0;
            return;
        }
        else  if(!T[flag][rt].ch[1]){
            rt=T[flag][rt].ch[0];
            T[flag][rt].fa=0;
            return;
        }
        int lb=ne(flag,0),oldroot=rt;
        splay(flag,lb);
        T[flag][T[flag][oldroot].ch[1]].fa=root[flag];
        T[flag][root[flag]].ch[1]=T[flag][oldroot].ch[1];
    }
    
    int main(){
    //    freopen("temp.in","r",stdin);
        
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&head[i]);
            tail[i]=head[i];
        }
        for(int i=1;i<n;i++)  inc(0,abs(head[i]-head[i+1]));
        int pos=root[0];
        while(T[0][pos].ch[0])  pos=T[0][pos].ch[0];
        ans1=T[0][pos].v;
        
        for(int i=1;i<=n;i++)  inc(1,head[i]);
        for(int i=1;i<=n;i++){
            splay(1,i);
            if(T[1][root[1]].num>1)  ans2=0;
            ans2=min(ans2,abs(T[1][root[1]].v-T[1][ne(1,0)].v));
            ans2=min(ans2,abs(T[1][root[1]].v-T[1][ne(1,1)].v));
        }
        
        char opt[10];
        int t1,t2;
        for(int i=0;i<m;i++){
            scanf("%s",opt);
    //        insert
            if(opt[4]=='R'){
                scanf("%d%d",&t1,&t2);
                
                del(0,abs(tail[t1]-head[t1+1]));
                inc(0,abs(t2-tail[t1]));
                inc(0,abs(t2-head[t1+1]));
                tail[t1]=t2;
                int pos=root[0];
                while(T[0][pos].ch[0])  pos=T[0][pos].ch[0];
                ans1=T[0][pos].v;
                
                inc(1,t2);
                if(T[1][root[1]].num>1)  ans2=0;
                ans2=min(ans2,abs(T[1][root[1]].v-T[1][ne(1,0)].v));
                ans2=min(ans2,abs(T[1][root[1]].v-T[1][ne(1,1)].v));
            }
    //        min_gap
            else  if(opt[4]=='G'){
                printf("%d
    ",ans1);
            }
    //        min_sort_gap
            else{
                printf("%d
    ",ans2);
            }
        }
        
        return 0;
    }
  • 相关阅读:
    静态切割窗体+关联对话框
    POJ 2236 Wireless Network(并查集)
    怎样学习(3):迭代学习,精益求精
    【菜鸟也疯狂UML系列】——概述
    OpenGL 资源汇编
    vue之mapMutaions的使用 && vuex中 action 用法示例 && api.js的使用
    内置组件 && vue中强大的缓存机制之keep-alive
    vue生命周期及使用 && 单文件组件下的生命周期
    vue中遇到的坑 --- 变化检测问题(数组相关)
    如何去除vue项目中的 # --- History模式
  • 原文地址:https://www.cnblogs.com/ZYBGMZL/p/13891810.html
Copyright © 2011-2022 走看看