题解 Luogu P1110 【[ZJOI2007]报表统计】
感谢 @cmy962085349 提供的hack数据,已经改对了。
先声明,我好像是题解里写双$fhq$ $treap$里唯一能过的...(最后两个点啊)
思路:首先看题目,$MIN_GAP_SORT$ 明显是求它的前驱与后继(可能有相同的),所以就用平衡树,但是又要求两个相邻的数的差,就可以有再开一个平衡树存放差值
实现:抛开奇奇怪怪的的题面,主要考虑这三个操作:
1、$INSERT$ $i$ $k$:
这个很简单,用链表就行了(数组模拟的),但是要注意,插入的时候,要接着上一个在这插入的,还要做双向链表,数组要记得开两倍
最重要的是,插入了以后,这个数的前一个数与后一个数的差要在存放相邻两个数的差的$fhq$ $treap$里删除,并插入这个数与前一个数的差和这个数与后一个数的差要存进去
2、$MIN_GAP$:
做完插入,就在存差的$fhq$ $treap$查$rank$$1$好了(最左边的那个节点)
3、$MIN_SORT_GAP$:
为了避免查前驱与后继时出现自己(不是另一个与自己相同的数),所以插入时(分裂后,合并前,这样正好符合查前驱与后继的标准)就比较取小,询问时直接输出就好了
P.S. 似乎经过 @cmy962085349 的 $hack$ 数据更正以后,似乎并不需要过于卡常了(原来代码需要疯狂卡常)(说明题解里双平衡树还是因为写错了而 $Tle$ 了后面两个点),似乎不用 $cin$ 与 $cout$ 就能过,不需要加什么 $register$ 了(虽然我还是加了)
附上AC代码:
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<iostream>
using namespace std; struct tree{//存每个值的数(不是差)
int size,val,dat,l,r;
}tr[1000005];//数组记得开两倍 int s_tr,root,n,m,x,y,z,a[1000005],b[1000005],c[1000005]; int min_sort_gap;//MIN_SORT_GAP的答案 inline int abs(int a){
return a<0?-a:a;
} inline int min(int a,int b){
return a<b?a:b;
} //fhq treap常规操作 inline int new_tr(int val){
tr[++s_tr].val=val;
tr[s_tr].size=1;
tr[s_tr].dat=rand();
return s_tr;
} inline void update(int p){
tr[p].size=tr[tr[p].l].size+tr[tr[p].r].size+1;
} void split(int p,int k,int &x,int &y){
if(!p){
x=y=0;
return;
}
if(tr[p].val<=k)x=p,split(tr[p].r,k,tr[p].r,y);
else y=p,split(tr[p].l,k,x,tr[p].l);
update(p);
} int merge(int x,int y){
if(!x||!y)return x+y;
if(tr[x].dat>tr[y].dat){
tr[x].r=merge(tr[x].r,y);
update(x);
return x;
}
else {
tr[y].l=merge(x,tr[y].l);
update(y);
return y;
}
} inline int Max(int x){//一棵fhq(可能是分裂后)中最大的
while(tr[x].r)x=tr[x].r;
return tr[x].val;
} inline int Min(int y){//一棵fhq(可能是分裂后)中最大的
while(tr[y].l)y=tr[y].l;
return tr[y].val;
} inline void insert(int val){
split(root,val,x,y);
if(tr[x].size)//要有才行
min_sort_gap=min(min_sort_gap,abs(val-Max(x)));
if(tr[y].size)//要有才行
min_sort_gap=min(min_sort_gap,abs(Min(y)-val));
root=merge(merge(x,new_tr(val)),y);
} //存差值的fhq treap struct tree1{
int size,val,dat,l,r;
}tr1[1000005]; int s_tr1,root1; inline int new_tr1(int val){
tr1[++s_tr1].val=val;
tr1[s_tr1].size=1;
tr1[s_tr1].dat=rand();
return s_tr1;
} inline void update1(int p){
tr1[p].size=tr1[tr1[p].l].size+tr1[tr1[p].r].size+1;
} void split1(int p,int k,int &x,int &y){
if(!p){
x=y=0;
return;
}
if(tr1[p].val<=k)x=p,split1(tr1[p].r,k,tr1[p].r,y);
else y=p,split1(tr1[p].l,k,x,tr1[p].l);
update1(p);
} int merge1(int x,int y){
if(!x||!y)return x+y;
if(tr1[x].dat>tr1[y].dat){
tr1[x].r=merge1(tr1[x].r,y);
update1(x);
return x;
}
else {
tr1[y].l=merge1(x,tr1[y].l);
update1(y);
return y;
}
} inline void insert1(int val){
split1(root1,val,x,y);
root1=merge1(merge1(x,new_tr1(val)),y);
} inline void delete_val(int val){//这棵fhq要能支持删除
split1(root1,val,x,z);
split1(x,val-1,x,y);
y=merge1(tr1[y].l,tr1[y].r);
root1=merge1(merge1(x,y),z);
} inline int Min1(int y){
while(tr1[y].l)y=tr1[y].l;
return tr1[y].val;
} char s[101];//卡常 inline int read(){//卡常
int r=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')r=(r<<1)+(r<<3)+c-'0',c=getchar();
return r*f;
} int main(){
srand(time(0));
n=read(),m=read();
min_sort_gap=1e9+10;
for(register int i=1;i<=n;i++){//卡常
a[i]=read();
insert(a[i]);
}
for(register int i=1;i<n;i++)//卡常减少if
insert1(abs(a[i+1]-a[i])),c[i]=i+1;
for(register int i=2;i<=n;i++)//卡常减少if,n+1是因为可能在第n个后面插入
b[i]=i-1;
b[n+1]=n;
int cnt=n;
for(register int i=1;i<=m;i++){//卡常
scanf("%s",s);
if(s[0]=='I'){
int j=read(),k=read();
delete_val(abs(a[j+1]-a[b[j+1]]));//因为插入后不在一起了,删除
insert1(abs(a[b[j+1]]-k));//插入后多了两个差值(不算删除的)
if(j<n)insert1(abs(k-a[j+1]));//可能插在第n个的后面
a[++cnt]=k;//放进数组,这件事一定要在上述操作以后做,不然若连续插入在第n个数以后就挂了,因为第一次cnt+1后会直接取代n+1,b[n+1]也就没什么用了
b[cnt]=b[j+1];//数组模拟链表
c[cnt]=j+1;
c[b[j+1]]=cnt;//记得修改前一个与后一个的指向
b[j+1]=cnt;
insert(k);
}
else {
if(s[4]=='G')printf("%d\n",Min1(root1));//整棵fhq里最小的
else printf("%d\n",min_sort_gap);
}
}
return 0;
}
再次感谢 @cmy962085349
完结偷偷撒花!(✿✿ヽ(°▽°)ノ✿)
题解 Luogu P1110 【[ZJOI2007]报表统计】的更多相关文章
- Luogu P1110 [ZJOI2007]报表统计 multiset
沿用了学长的$multiset$ 然后这道题可以看到我的程序中有两行注释,它在我看来和他们下面的代码没区别,但是我们发现,C++会先调用后面的参数,所以$--it$会被先执行 ... ... ... ...
- 洛谷 P1110 [ZJOI2007]报表统计 解题报告
P1110 [ZJOI2007]报表统计 题目描述 \(Q\)的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小\(Q\)希望可以帮妈妈分担一些工作,作为她的生日礼物之一. 经过仔细 ...
- P1110 [ZJOI2007]报表统计
题目描述 Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一. 经过仔细观察,小Q发现统计一张报表实际上是维护一个非负整数数列,并 ...
- P1110 [ZJOI2007]报表统计 (multiset)
[题目链接] https://www.luogu.org/problemnew/show/P1110 有以下三种操作: INSERT i k:在原数列的第i个元素后面添加一个新元素k:如果原数列的第i ...
- 2018.11.09 洛谷P1110 [ZJOI2007]报表统计(multiset)
传送门 sb题. 直接用两个multisetmultisetmultiset维护相邻两个数的差值和所有数的前驱后继. 插入一个数的时候更新一下就行了. 代码: #include<bits/std ...
- bzoj P1058 [ZJOI2007]报表统计——solution
1058: [ZJOI2007]报表统计 Time Limit: 15 Sec Memory Limit: 162 MB Submit: 4099 Solved: 1390 [Submit][St ...
- 【BZOJ1058】[ZJOI2007]报表统计 STL
[BZOJ1058][ZJOI2007]报表统计 Description 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一.经 ...
- [ZJOI2007]报表统计(splay,堆)
[ZJOI2007]报表统计(luogu) Description 题目描述 Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一. ...
- bzoj1058: [ZJOI2007]报表统计
set.操作:insert(u,v)在u后面插入v,若u后面已插入过,在插入过的后面插入.mingap求出序列两两之间差值的最小值.minsortgap求出排序后的序列两两之间的最小值.用multis ...
- BZOJ 1058: [ZJOI2007]报表统计( 链表 + set )
这种题用数据结构怎么写都能AC吧...按1~N弄个链表然后每次插入时就更新答案, 用set维护就可以了... --------------------------------------------- ...
随机推荐
- NoSql数据库Redis系列(3)——Redis数据持久化(RDB)
大家都知道 Redis 是一个内存数据库,所谓内存数据库,就是将数据库中的内容保存在内存中,这与传统的MySQL,Oracle等关系型数据库直接将内容保存到硬盘中相比,内存数据库的读写效率比传统数据库 ...
- 在Windows下编译Cef3.2623并加入mp3、mp4支持(附带源码包和最终DLL)《转》
https://blog.csdn.net/zhuhongshu/article/details/54193842 源码包下载地址:点我下载 最终Dll.Lib.PDB.头文件下载地址(release ...
- 基因表达半衰期 | mRNA Half-Life
做单细胞RNA-seq分析,自然就能想到我们测到的其实是一个概率学的东西,就像女士品茶里的酵母的泊松分布一样. 真实的细胞里,一切都是连续的,从DNA到mRNA到蛋白,是有一个时间间隔的,每一个pro ...
- 字节码(.class)文件的加载过程
类加载 在Java代码中,类型的加载.连接与初始化过程都是在程序运行期间完成的. 类型可以是Class,Interface, 枚举等. Java虚拟机与程序的生命周期 在如下几种情况下,Java虚拟机 ...
- GRU和LSTM比较
比较: https://www.jianshu.com/p/3774d46b665e https://blog.csdn.net/sinat_33741547/article/details/8282 ...
- 一个Redis实例适合存储不同应用程序的数据吗?
Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念. Redis是一个字典结构的存储服务器,而实际上一个Redis实例提供了多个用来存储数据 ...
- nginx多层反向代理获取客户端真实ip
访问路径: 用户 --> www.chinasoft.cn(nginx反向代理) --> www.chinasoft.com(nginx反向代理) --> python服务端程序 经 ...
- 搭建iscsi存储系统(一)
(1).DAS.SAN.NAS三种存储方式 参考:https://blog.csdn.net/qq_23348071/article/details/73963407 DAS全称Direct-Atta ...
- Linux系统调优——内核相关参数(五)
修改内核参数有3种办法:一种临时修改,两种永久修改. 临时修改是使用sysctl [选项] [参数名=值]命令:永久修改是修改/etc/sysctl.conf文件或修改/proc/sys/目录下的对应 ...
- 123457123457#0#-----com.tym.PuzzleGame28--前拼后广--日常pt-tym
com.tym.PuzzleGame28--前拼后广--日常pt-tym