BZOJ1058: [ZJOI2007]报表统计

BZOJ1058: [ZJOI2007]报表统计

Description

  小Q的妈妈是一个出纳,经常需要做一些统计报表的工作。今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一。
经过仔细观察,小Q发现统计一张报表实际上是维护一个可能为负数的整数数列,并且进行一些查询操作。
在最开始的时候,有一个长度为N的整数序列,并且有以下三种操作:
INSERT i k 在原数列的第i个元素后面添加一个新元素k;
如果原数列的第i个元素已经添加了若干元素,则添加在这些元素的最后(见下面的例子)
MIN_GAP 查询相邻两个元素的之间差值(绝对值)的最小值
MIN_SORT_GAP 查询所有元素中最接近的两个元素的差值(绝对值)
例如一开始的序列为 5 3 1
执行操作INSERT 2 9将得到: 5 3 9 1
此时MIN_GAP为2,MIN_SORT_GAP为2。
再执行操作INSERT 2 6将得到: 5 3 9 6 1
注意这个时候原序列的第2个元素后面已经添加了一个9,此时添加的6应加在9的后面。
这个时候MIN_GAP为2,MIN_SORT_GAP为1。
于是小Q写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?

Input

第一行包含两个整数N,M,分别表示原数列的长度以及操作的次数。
第二行为N个整数,为初始序列。
接下来的M行每行一个操作,即“INSERT i k”,“MIN_GAP”,“MIN_SORT_GAP”中的一种(无多余空格或者空行)。

Output

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

Sample Input

3 5
5 3 1
INSERT 2 9
MIN_SORT_GAP
INSERT 2 6
MIN_GAP
MIN_SORT_GAP

Sample Output

2
2
1

HINT

N , M ≤500000 对于所有的数据,序列内的整数不超过5*10^8。


题解Here!

 

恶心到极致的卡常题。。。
维护两个Treap即可。 
为什么不用Splay
因为这个题目BZOJ用事实告诉我们:Splay的常数是Treap的许多倍。。。
第一颗Treap:维护每个点,每次新加入一个点时,找到前驱后继,维护第3个操作的答案。 
第二颗Treap:每次加入点时,维护相邻两个点之差的绝对值。
然后就没了。
但是这题疯狂卡常。。。
借鉴了网上的几个优化:
  1. 对于第2个操作,我们注意到,加入一个点位置是pos时,pospos1的差值不会消失,所以可以用一个ans来维护pos与前驱的之间的值。
  2. pospos+1之间可能加入数字,所以用Treap维护。不过,若差值小于ans,就不用再加入Treap中了。
  3. 还有,对于第3个操作,在统计是只要发现有两个数字相同,就做个标记,到后面询问时直接输出0即可。

以上所说的差值都要加绝对值。

然后就可以跑了。。。

附代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 500010
#define MAX 999999999
using namespace std;
int n,m,minn=MAX;
int head[MAXN],last[MAXN];
bool flag;
struct node{
    node* son[2];
    int w,v,s,flag;
    node(){
        son[0]=son[1]=NULL;
        w=rand();
        v=0;
        s=flag=1;
    }
};
node* one;node* two;
inline int read(){
    int date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    return date*w;
}
inline void write(int x){
    if(x<0){putchar('-');x=-x;}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
inline long long abs(const long long x){return x>0?x:-x;}
inline long long min(const long long x,const long long y){return x<y?x:y;}
void maintain(node* &u){
    u->s=u->flag;
    if(u->son[0]!=NULL)u->s+=u->son[0]->s;
    if(u->son[1]!=NULL)u->s+=u->son[1]->s;
}
void turn(node* &u,int f){
    node* t=u->son[f^1];
    u->son[f^1]=t->son[f];
    t->son[f]=u;
    maintain(u);
    maintain(t);
    u=t;
}
void insert(node* &u,int x){
    if(u==NULL){
        u=new node;
        u->v=x;
        return;
    }
    else if(u->v==x){
        u->flag++;
        maintain(u);
        if(flag)minn=-1;
        return;
    }
    int y=u->v<x?1:0;
    insert(u->son[y],x);
    if(u->son[y]->w>u->w)turn(u,y^1);
    else maintain(u);
}
void remove(node* &u,int x){
    if(u==NULL)return;
    if(u->v==x){
        if(u->flag>1)u->flag--;
        else{
            if(u->son[0]==NULL&&u->son[1]==NULL)u=NULL;
            else if(u->son[0]!=NULL&&u->son[1]!=NULL){
                if(u->son[0]->w>u->son[1]->w){
                    turn(u,1);
                    remove(u->son[1],x);
                }
                else{
                    turn(u,0);
                    remove(u->son[0],x);
                }
            }
            else{
                if(u->son[0]==NULL)u=u->son[1];
                else u=u->son[0];
            }
        }
        if(u!=NULL)maintain(u);
    }
    else{
        if(u->v>x)remove(u->son[0],x);
        else if(u->v<x)remove(u->son[1],x);
        if(u!=NULL)maintain(u);
    }
}
int kth(node* u,int k){
    if(k<0||k>u->s||u==NULL)return 0;
    int lsons=0;
    if(u->son[0]!=NULL)lsons=u->son[0]->s;
    if(k>=lsons+1&&k<=lsons+u->flag)return u->v;
    if(k<=lsons)return kth(u->son[0],k);
    else return kth(u->son[1],k-lsons-u->flag);
}
void front(node* u,int k,int &ans){
    if(u==NULL)return;
    if(u->v<k){
        if(u->v>ans)ans=u->v;
        if(u->son[1]!=NULL)front(u->son[1],k,ans);
    }
    else if(u->v>=k)
    if(u->son[0]!=NULL)front(u->son[0],k,ans);
}
void next(node* u,int k,int &ans){
    if(u==NULL)return;
    if(u->v>k){
        if(u->v<ans)ans=u->v;
        if(u->son[0]!=NULL)next(u->son[0],k,ans);
    }
    else if(u->v<=k)
    if(u->son[1]!=NULL)next(u->son[1],k,ans);
}
void update(int v){
    int front_v=-MAX,next_v=MAX;
    front(one,v,front_v);next(one,v,next_v);
    minn=min(minn,min(abs(front_v-v),abs(next_v-v)));
}
void work(){
    char ch[15];
    int x,y,ans=MAX;
    while(m--){
        scanf("%s",ch);
        if(ch[0]=='I'){
            x=read();y=read();
            flag=true;
            insert(one,y);
            if(minn!=-1)update(y);
            flag=false;
            ans=min(ans,abs(last[x]-y));
            if(x!=n){
                if(abs(head[x+1]-y)<ans)insert(two,abs(head[x+1]-y));
                if(abs(head[x+1]-last[x])<ans)remove(two,abs(head[x+1]-last[x]));
            }
            last[x]=y;
        }
        else if(ch[4]=='G'){write(min(ans,kth(two,1)));putchar('\n');}
        else{write(minn==-1?0:minn);putchar('\n');}
    }
}
void init(){
    srand(2002);
    n=read();m=read();
    flag=true;
    insert(one,-MAX);insert(one,MAX);
    for(int i=1;i<=n;i++){
        int x=read();
        head[i]=last[i]=x;
        insert(one,x);
        if(minn!=-1)update(x);
    }
    flag=false;
    for(int i=1;i<n;i++)insert(two,abs(head[i]-head[i+1]));
}
int main(){
    init();
    work();
    return 0;
}

 

posted @   符拉迪沃斯托克  阅读(249)  评论(0编辑  收藏  举报
编辑推荐:
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
阅读排行:
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单
Live2D
欢迎阅读『BZOJ1058: [ZJOI2007]报表统计』
点击右上角即可分享
微信分享提示