勤快的love枫[ZJOI2007]
题目描述
小绝恋love 枫是一个出纳,经常需要做一些统计报表的工作。今天是绝恋love 枫的生日,小绝恋love 枫希望可以帮爸爸分担一些工作,作为他的生日礼物之一。经过仔细观察,小绝恋love 枫发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作。在最开始的时候,有一个长度为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。于是小绝恋love 枫写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?
输入
第一行包含两个整数N,M,分别表示原数列的长度以及操作的次数。
第二行为N 个整数,为初始序列。
接下来的M 行每行一个操作,即“INSERT i k”,“MIN_GAP”,“MIN_SORT_GAP”中的一种(无多余空格或者空行)。
输出
对于每一个“MIN_GAP”和“MIN_SORT_GAP”命令,输出一行答案即可。
样例输入
3 5
5 3 1
INSERT 2 9
MIN_SORT_GAP
INSERT 2 6
MIN_GAP
MIN_SORT_GAP
样例输出
2
2
1
提示
对于30% 的数据,N≤1000,M≤5000
对于100% 的数据,N,M≤50000
对于所有的数据,序列内的整数不超过5*10^8。
题解
一道显而易见的数据结构题,在数据结构题里几乎算不用动脑子的那种。前后最小的一下子想到钢哥讲过的垃圾堆,维护两个堆就可以实现有效答案的添加和删除。原数列也可以用一个副本数组,只维护目前最靠前和最靠后的值(考试时忘了下一个位置的开头元素还需要记录,炸了不少分)。但是整个序列中最相近的两个元素,就有些犯难。明明知道就应该建个平衡树找前驱后继,尴尬的情况是平衡树只打过Treap,Treap只打过两道题,还是一两周之前的事了,考场上打挂可能性极大。权衡了一下,还是拿了个数组暴力排序,唯一的优化是如果最小值已经为0就不再改动。算上这道题平衡树也只打过三道,简直不能算做过题。书到用时方恨少,事非经过不知难,从第一次见到这句话到现在已经有些年了,理解倒是越来越深了= =。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<cmath>
using namespace std;
const int sj=;
int n,m,a[sj],a1,a2,mi,g,q,h,jq,hj,size,d[sj];
priority_queue<int,vector<int>,greater<int> > qi;
priority_queue<int,vector<int>,greater<int> > du;
char c[];
struct tree
{
int l,r,v,rnd;
}t[sj];
int bj(int x,int y)
{
return x<y?x:y;
}
void lturn(int &x)
{
int tt=t[x].r;
t[x].r=t[tt].l;
t[tt].l=x;
x=tt;
}
void rturn(int &x)
{
int tt=t[x].l;
t[x].l=t[tt].r;
t[tt].r=x;
x=tt;
}
void query_pre(int k,int x)
{
if(k==) return;
if(t[k].v<x)
{
q=k;
query_pre(t[k].r,x);
}
else query_pre(t[k].l,x);
}
void query_beh(int k,int x)
{
if(k==) return;
if(t[k].v>x)
{
h=k;
query_beh(t[k].l,x);
}
else query_beh(t[k].r,x);
}
void cr(int &x,int y)
{
if(x==)
{
size++;
x=size;
t[x].rnd=rand();
t[x].v=y;
return;
}
if(t[x].v==y)
{
jq=hj=y;
q=h=;
return;
}
if(y>t[x].v)
{
cr(t[x].r,y);
if(t[x].rnd>t[t[x].r].rnd) lturn(x);
}
if(y<t[x].v)
{
cr(t[x].l,y);
if(t[x].rnd>t[t[x].l].rnd) rturn(x);
}
}
void init()
{
scanf("%d%d",&n,&m);
mi=0x7fffffff;
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
if(i!=) qi.push(abs(a[i]-a[i-]));
if(mi)
{
q=h=-;
jq=hj=;
cr(g,a[i]);
if(q==-)
{
query_beh(g,a[i]);
query_pre(g,a[i]);
if(q!=-||h!=-)
{
jq=(q==-)?0x7fffffff:t[q].v;
hj=(h==-)?0x7fffffff:t[h].v;
mi=bj(mi,abs(a[i]-jq));
mi=bj(mi,abs(a[i]-hj));
}
}
else mi=;
}
memcpy(d,a,sizeof(a));
}
}
void cl()
{
for(int i=;i<=m;i++)
{
scanf("%s",c);
if(c[]=='R')
{
scanf("%d%d",&a1,&a2);
if(a1!=n)
{
qi.push(abs(a2-a[a1+]));
du.push(abs(a[a1+]-d[a1]));
}
qi.push(abs(a2-d[a1]));
d[a1]=a2;
if(mi)
{
q=h=-;
jq=hj=;
cr(g,a2);
if(q==-)
{
query_beh(g,a2);
query_pre(g,a2);
if(q!=-||h!=-)
{
jq=(q==-)?0x7fffffff:t[q].v;
hj=(h==-)?0x7fffffff:t[h].v;
mi=bj(mi,abs(a2-jq));
mi=bj(mi,abs(a2-hj));
}
}
else mi=;
}
}
if(c[]=='G')
{
while(!qi.empty()&&!du.empty()&&qi.top()==du.top())
{
qi.pop();
du.pop();
}
printf("%d\n",qi.top());
}
if(c[]=='S') printf("%d\n",mi);
}
}
int main()
{
init();
cl();
return ;
}
love
在cogs上看到了这题,交了一下RE,发现数据范围是十倍……调了数组大小再交一遍,居然TLE了!据说堆可能会炸掉,不得已又改成了线段树。跑得确实快了,可是比堆难写得多啊。差点上两百行【抵制恶意缩行不良风气,从我做起!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
const int sj=;
int n,m,a[sj],a1,a2,mi,g,q,h,jq,hj,size,d[sj],last;
struct xs
{
int v,l,r;
}xds[sj*];
char c[];
struct tree
{
int l,r,v,rnd;
}t[sj];
int bj(int x,int y)
{
return x<y?x:y;
}
void lturn(int &x)
{
int tt=t[x].r;
t[x].r=t[tt].l;
t[tt].l=x;
x=tt;
}
void rturn(int &x)
{
int tt=t[x].l;
t[x].l=t[tt].r;
t[tt].r=x;
x=tt;
}
void query_pre(int k,int x)
{
if(k==) return;
if(t[k].v<x)
{
q=k;
query_pre(t[k].r,x);
}
else query_pre(t[k].l,x);
}
void query_beh(int k,int x)
{
if(k==) return;
if(t[k].v>x)
{
h=k;
query_beh(t[k].l,x);
}
else query_beh(t[k].r,x);
}
void cr(int &x,int y)
{
if(x==)
{
size++;
x=size;
t[x].rnd=rand();
t[x].v=y;
return;
}
if(t[x].v==y)
{
jq=hj=y;
q=h=;
return;
}
if(y>t[x].v)
{
cr(t[x].r,y);
if(t[x].rnd>t[t[x].r].rnd) lturn(x);
}
if(y<t[x].v)
{
cr(t[x].l,y);
if(t[x].rnd>t[t[x].l].rnd) rturn(x);
}
}
void build(int x,int z,int y)
{
xds[x].l=z;
xds[x].r=y;
xds[x].v=0x7fffffff;
if(z==y) return;
int mid=(z+y)>>;
build(x<<,z,mid);
build((x<<)|,mid+,y);
}
void update(int x,int z,int y)
{
if(xds[x].l==xds[x].r&&xds[x].l==z)
{
xds[x].v=y;
return;
}
int mid=(xds[x].l+xds[x].r)>>;
if(z<=mid)
{
update(x<<,z,y);
xds[x].v=bj(xds[(x<<)|].v,xds[x<<].v);
}
else
{
update((x<<)|,z,y);
xds[x].v=bj(xds[(x<<)|].v,xds[x<<].v);
}
}
void init()
{
scanf("%d%d",&n,&m);
mi=0x7fffffff;
build(,,sj*-);
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
if(i!=) update(,i-,abs(a[i]-a[i-]));
if(mi)
{
q=h=-;
jq=hj=;
cr(g,a[i]);
if(q==-)
{
query_beh(g,a[i]);
query_pre(g,a[i]);
if(q!=-||h!=-)
{
jq=(q==-)?0x7fffffff:t[q].v;
hj=(h==-)?0x7fffffff:t[h].v;
mi=bj(mi,abs(a[i]-jq));
mi=bj(mi,abs(a[i]-hj));
}
}
else mi=;
}
}
memcpy(d,a,sizeof(a));
last=n-;
}
void cl()
{
for(int i=;i<=m;i++)
{
scanf("%s",c);
if(c[]=='R')
{
scanf("%d%d",&a1,&a2);
last++;
update(,last,abs(a2-d[a1]));
update(,a1,abs(a2-a[a1+]));
d[a1]=a2;
if(mi)
{
q=h=-;
jq=hj=;
cr(g,a2);
if(q==-)
{
query_beh(g,a2);
query_pre(g,a2);
if(q!=-||h!=-)
{
jq=(q==-)?0x7fffffff:t[q].v;
hj=(h==-)?0x7fffffff:t[h].v;
mi=bj(mi,abs(a2-jq));
mi=bj(mi,abs(a2-hj));
}
}
else mi=;
}
}
if(c[]=='G') printf("%d\n",xds[].v);
if(c[]=='S') printf("%d\n",mi);
}
}
int main()
{
init();
cl();
return ;
}
form
勤快的love枫[ZJOI2007]的更多相关文章
- bzoj-1096 1096: [ZJOI2007]仓库建设(斜率优化dp)
题目链接: 1096: [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L ...
- BZOJ 1096: [ZJOI2007]仓库建设 [斜率优化DP]
1096: [ZJOI2007]仓库建设 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4201 Solved: 1851[Submit][Stat ...
- 【BZOJ1060】[ZJOI2007]时态同步 树形DP
[BZOJ1060][ZJOI2007]时态同步 Description 小Q在电子工艺实习课上学习焊接电路板.一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字1,2,3-.进行标号.电路 ...
- BZOJ 1093 [ZJOI2007] 最大半连通子图(强联通缩点+DP)
题目大意 题目是图片形式的,就简要说下题意算了 一个有向图 G=(V, E) 称为半连通的(Semi-Connected),如果满足图中任意两点 u v,存在一条从 u 到 v 的路径或者从 v 到 ...
- BZOJ4011: [HNOI2015]落忆枫音
Description 「恒逸,你相信灵魂的存在吗?」 郭恒逸和姚枫茜漫步在枫音乡的街道上.望着漫天飞舞的红枫,枫茜突然问出 这样一个问题. 「相信吧.不然我们是什么,一团肉吗?要不是有灵魂……我们 ...
- 【BZOJ】【1059】【ZJOI2007】矩阵游戏
二分图完美匹配/匈牙利算法 如果a[i][j]为黑点,我们就连边 i->j ,然后跑二分图最大匹配,看是否有完美匹配. <_<我们先考虑行变换:对于第 i 行,如果它第 j 位是黑点 ...
- 【BZOJ】【4011】【HNOI2015】落忆枫音
拓扑排序+DP 题解:http://blog.csdn.net/PoPoQQQ/article/details/45194103 http://www.cnblogs.com/mmlz/p/44487 ...
- bzoj1058: [ZJOI2007]报表统计
set.操作:insert(u,v)在u后面插入v,若u后面已插入过,在插入过的后面插入.mingap求出序列两两之间差值的最小值.minsortgap求出排序后的序列两两之间的最小值.用multis ...
- 洛谷 P1169 [ZJOI2007]棋盘制作
2016-05-31 14:56:17 题目链接: 洛谷 P1169 [ZJOI2007]棋盘制作 题目大意: 给定一块矩形,求出满足棋盘式黑白间隔的最大矩形大小和最大正方形大小 解法: 神犇王知昆的 ...
随机推荐
- R语言统计分析技术研究——岭回归技术的原理和应用
岭回归技术的原理和应用 作者马文敏 岭回归分析是一种专用于共线性分析的有偏估计回归方法,实质上是一种改良的最小二乘估计法,通过放弃最小二乘法的无偏性,以损失部分信息,降低精度为代价获得回归系数更为符合 ...
- PHP设计模式:简单工厂
示例代码详见https://github.com/52fhy/design_patterns 简单工厂 简单工厂模式的工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例. 也就是使用的 ...
- dubbo与zookeeper的关系
Dubbo建议使用Zookeeper作为服务的注册中心. 1. Zookeeper的作用: zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知道,简单来说就是 ...
- hibernate 返回对象指定属性,需要返回的列,可以直接返回 对象属性
// hibernate 返回对象指定属性,需要返回的列,可以直接返回 对象属性 @Override public TeamPlan getTeamPlanByBaoMingId(String bao ...
- jquery 表格行计算
表格行计算 总金额: function jisuanTrJinE(obj){ var curTab = $(obj).closest("table"); var curTr = $ ...
- 【Android Developers Training】 105. 显示一个位置地址
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- Vijos 1006 晴天小猪历险记之Hill 单源单汇最短路
背景 在很久很久以前,有一个动物村庄,那里是猪的乐园(^_^),村民们勤劳.勇敢.善良.团结-- 不过有一天,最小的小小猪生病了,而这种病是极其罕见的,因此大家都没有储存这种药物.所以晴天小猪自告奋勇 ...
- [图形学] Chp14 GLU曲面裁剪函数程序示例及样条表示遗留问题
样条表示这章已经看完,最后的GLU曲面裁剪函数,打算按书中的示例实现一下,其中遇到了几个问题. 先介绍一下GLU曲面裁剪函数的使用方法. 1 裁剪函数是成对出现的: gluBeginTrim和gluE ...
- 常见的排序算法总结(JavaScript)
引言 排序算法是数据结构和算法之中的基本功,无论是在笔试还是面试,还是实际运用中都有着很基础的地位.这不正直七月,每年校招的备战期,所以想把常见的排序算法记录下来.在本篇文章中的排序算法使用 Java ...
- 改进log4go的一些设想
log4go 的 4.0.2 版本(https://github.com/ccpaging/log4go/tree/4.0.2)发布以后, 看了看别的 go 语言日志文件设计.发现了一篇好文: log ...