1058. [ZJOI2007]报表统计【平衡树-splay+堆】

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。

操作1用splay维护区间
操作2在进行操作1的时候从堆里删除旧的相邻值然后插入两个新的相邻值,
然后在到2的时候输出堆顶
注意可删除堆的操作(将删除的数放到del堆里,当两堆堆顶相同就pop
操作3再开一个splay维护数就好了,每次查询下前驱后继,开个堆维护下最小值

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<queue>
  6 #include<algorithm>
  7 #define N (2000000+1000)
  8 using namespace std;
  9 int last[N],Val[N],Father[N],Son[N][2],ins[N],Cnt[N],Size[N];
 10 int INF,n,m,a[N],sz=1000000,SZ,ROOT,root;
 11 priority_queue<int,vector<int>,greater<int> >ans;
 12 priority_queue<int,vector<int>,greater<int> >del;
 13 priority_queue<int,vector<int>,greater<int> >minnum;
 14
 15 int Get(int x){return Son[Father[x]][1]==x;}
 16 void Update(int x){Size[x]=Cnt[x]+Size[Son[x][0]]+Size[Son[x][1]];}
 17 int Pre(int now){now=Son[now][0]; while (Son[now][1]) now=Son[now][1]; return now;}
 18 int Next(int now){now=Son[now][1]; while (Son[now][0]) now=Son[now][0]; return now;}
 19
 20 void Rotate(int x)
 21 {
 22     int wh=Get(x);
 23     int fa=Father[x],fafa=Father[fa];
 24     if (fafa) Son[fafa][Son[fafa][1]==fa]=x;
 25     Son[fa][wh]=Son[x][wh^1]; Father[fa]=x;
 26     if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
 27     Son[x][wh^1]=fa; Father[x]=fafa;
 28     Update(fa);    Update(x);
 29 }
 30
 31 void Splay(int x,int tar,int &Root)
 32 {
 33     for (int fa; (fa=Father[x])!=tar; Rotate(x))
 34         if (Father[fa]!=tar)
 35             Rotate(Get(fa)==Get(x)?fa:x);
 36     if (!tar) Root=x;
 37 }
 38
 39 void Insert(int x)
 40 {
 41     if (!root)
 42     {
 43         root=++sz;
 44         Size[sz]=Cnt[sz]=1;
 45         Val[sz]=x;
 46         return;
 47     }
 48     int now=root,fa=0;
 49     while (1)
 50     {
 51         if (x==Val[now])
 52         {
 53             Cnt[now]++;
 54             Update(now);
 55             Splay(now,0,root);
 56             return;
 57         }
 58         fa=now,now=Son[now][x>Val[now]];
 59         if (now==0)
 60         {
 61             Size[++sz]=Cnt[sz]=1;
 62             Val[sz]=x;
 63             Father[sz]=fa;
 64             Son[fa][x>Val[fa]]=sz;
 65             Splay(sz,0,root);
 66             return;
 67         }
 68     }
 69 }
 70
 71 int Build(int l,int r,int fa)
 72 {
 73     if (l>r) return 0;
 74     int mid=(l+r)>>1;
 75     Size[mid]=Cnt[mid]=1;
 76     Val[mid]=a[mid];
 77     Father[mid]=fa;
 78     Son[mid][0]=Build(l,mid-1,mid);
 79     Son[mid][1]=Build(mid+1,r,mid);
 80     return mid;
 81
 82 }
 83 int Findx(int x)
 84 {
 85     int now=ROOT;
 86     while (1)
 87         if (x<=Size[Son[now][0]])
 88             now=Son[now][0];
 89         else
 90         {
 91             x-=Size[Son[now][0]];
 92             if (x<=Cnt[now])
 93             {
 94                 Splay(now,0,ROOT);
 95                 return now;
 96             }
 97             x-=Cnt[now];
 98             now=Son[now][1];
 99         }
100 }
101 int Split(int x,int y)
102 {
103     Splay(x,0,ROOT); Splay(y,x,ROOT);
104     return y;
105 }
106
107 int main()
108 {
109     memset(&INF,0x3f,sizeof(INF));
110     scanf("%d%d",&n,&m); SZ=n+5;
111     for (int i=1;i<=n;++i)
112         scanf("%d",&a[i+1]);
113     a[1]=a[n+2]=INF;
114     for (int i=1;i<=n+2;++i)
115     {
116         Insert(a[i]);
117         if (Cnt[root]>1 && Val[root]!=INF) minnum.push(0);
118         else
119         {
120             int pre=Pre(root),next=Next(root);
121             if (pre) minnum.push(abs(Val[root]-Val[pre]));
122             if (next) minnum.push(abs(Val[root]-Val[next]));
123         }
124         if (i>1) ans.push(abs(a[i]-a[i-1]));
125         last[i]=i;
126     }
127     ROOT=Build(1,n+2,0);
128     sort(a+1,a+n+2+1);
129     for (int i=3;i<=n+1;++i)
130         minnum.push(abs(Val[i]-Val[i-1]));
131     for (int i=1;i<=m;++i)
132     {
133         char opt[10]; int x,y;
134         scanf("%s",opt);
135         if (opt[4]==‘R‘)
136         {
137             scanf("%d%d",&x,&y); x++;
138             int p=Split(last[x],x+1);
139             Val[++SZ]=y; Father[SZ]=p;
140             Son[p][0]=SZ;
141             ins[x]++;
142             Size[SZ]=Cnt[SZ]=1;
143             Splay(SZ,0,ROOT);
144             last[x]=SZ;
145             int pre=Pre(ROOT),next=Next(ROOT);
146             del.push(abs(Val[pre]-Val[next]));
147             ans.push(abs(Val[pre]-Val[SZ]));
148             ans.push(abs(Val[next]-Val[SZ]));
149             Insert(y);
150             if (Cnt[root]>1) minnum.push(0);
151             else
152             {
153                 pre=Pre(root),next=Next(root);
154                 minnum.push(abs(Val[root]-Val[pre]));
155                 minnum.push(abs(Val[root]-Val[next]));
156             }
157         }
158         if (opt[4]==‘G‘)
159         {
160             while (!del.empty() && del.top()==ans.top())
161                 del.pop(),ans.pop();
162             printf("%d\n",ans.top());
163         }
164         if (opt[4]==‘S‘)
165             printf("%d\n",minnum.top());
166     }
167 }

原文地址:https://www.cnblogs.com/refun/p/8685636.html

时间: 2024-10-12 15:38:25

1058. [ZJOI2007]报表统计【平衡树-splay+堆】的相关文章

[BZOJ 1058] [ZJOI2007] 报表统计 【平衡树】

题目链接:BZOJ - 1058 题目分析 这道题看似是需要在序列中插入一些数字,但其实询问的内容只与相邻的元素有关. 那么我们只要对每个位置维护两个数 Ai, Bi, Ai 就是初始序列中 i 这个位置的数, Bi 是在 i 这个位置insert的最后一个数. 那么在 i insert一个数 Num 的时候,造成的影响就是使得 Bi 和 A(i+1) 不再相邻,同时使 Bi 与 Num, Num 与 A(i+1) 相邻.然后将 Bi 更新为 Num. 这样就只需要实现一个multiset的功能

[BZOJ 1058][ZJOI2007]报表统计

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1058 题解 方法一:离线+离散化+线段树. 这个方式的常数太大,会T.我在洛谷跑最后两个点TLE了,在BZOJRE了. 具体说一下怎么做吧.首先把所有数离散化,把出现过的绝对值离散化.这样我们就能得到约n+m个数和n+m个绝对值.然后,维护两颗线段树,记录数据是否出现,并记录区间出现的最大值和最小值(因为在线段树上的点是从大到小的,假设我们添加了元素k,然后我们找它的数据排位(下标)),每添

bzoj 1058 [ZJOI2007]报表统计(set)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1058 [题意] 一个序列,提供插入,查询相邻最小差值,查询任意最小差值的操作. [思路] Set 用两个set,listed装所有的相邻差值,sorted装所有的数.然后用front[x],last[x]记录位置x上开始和结束的数. 对于Insert,维护listed:删除front[x+1]与last[x]的差值并插入两个新的差值,插入sorted后与前一个后一个作差更新答案. [

【BZOJ 1058】 [ZJOI2007]报表统计

1058: [ZJOI2007]报表统计 Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 2013  Solved: 708 [Submit][Status] Description 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一.经过仔细观察,小Q发现统计一张报表实际上是维护一个可能为负数的整数数列,并且进行一些查询操作.在最开始的时候,有一个长度为N的整数序列,并且有

BZOJ1058: [ZJOI2007]报表统计

1058: [ZJOI2007]报表统计 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1751  Solved: 614[Submit][Status] Description 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一.经过仔细观察,小Q发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作.在最开始的时候,有一个长度为N的整数序列,并且有以下三种操作

bzoj P1058 [ZJOI2007]报表统计——solution

1058: [ZJOI2007]报表统计 Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 4099  Solved: 1390 [Submit][Status][Discuss] Description 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工 作,作为她的生日礼物之一.经过仔细观察,小Q发现统计一张报表实际上是维护一个可能为负数的整数数列,并 且进行一些查询操作.在最开始的时候,有一个长

[补档][ZJOI2007] 报表统计

[ZJOI2007] 报表统计 题目 传送门 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一. 经过仔细观察,小Q发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作. 在最开始的时候,有一个长度为N的整数序列,并且有以下三种操作: INSERT i k 在原数列的第i个元素后面添加一个新元素k:如果原数列的第i个元素已经添加了若干元素,则添加在这些元素的最后(见下面的例子) MIN_GAP 查询相邻两个元

AC日记——[ZJOI2007]报表统计 bzoj 1058

1058 思路: 平衡树的题: 然而我的平衡树写一次炸一次QwQ: 而且各种tle: 所以stl水过: 代码: #include <set> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 1000005 class HeadType { private: int head

BZOJ 1058 ZJOI 2007 报表统计 平衡树

题目大意:给出一个序列,有几个操作,询问相邻两个数的差值的绝对值的最小值,排序后差值绝对值的最小值. 思路:简单用平衡树或者set水一下就行了. (我个沙茶最开始sort_min还用的set维护 CODE: #include <set> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 500010 #define I