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\n",ans1);
        }
//        min_sort_gap
        else{
            printf("%d\n",ans2);
        }
    }
    
    return 0;
}

 

posted @ 2020-10-28 16:29  ZYBGMZL  阅读(83)  评论(0编辑  收藏  举报