【SinGuLaRiTy-1011】 Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.

G2019级信息奥赛专项训练

题目

程序名

时间

内存

测试点

原子核研究

atomic.cpp

2s

256MB

10

球星

star.cpp

2s

256MB

10

跳跃

jump.cpp

2s

256MB

10

原子核研究(atomic.cpp)

题目描述

最近物理学家正在研究一些新的原子,称为X族。他们发现该族中的元素非常相近,但是其质量都不相同。质量越接近的越容易相互转化。现在,物理学家已经发明了一种设备,可以对X族的元素来进行以下三种操作:
1.generate M 产生质量为M的一个元素,如果已经存在,则该操作不产生作用。
2.romove M 销掉质量为M的元素,如果不存在质量为M的元素,则该操作不产生作用。
3.query 查询X族中质量最接近的两种元素的质量差的绝对值。如果此时X族中的元素个数小于2,则输出-1.
现在,请你写一个程序来模拟该设备的操作。

输入

输入包含多组测试数据,第一行一个整数t,表示测试数据的组数。对于每一组数据,第一行是一个整数n,表示有n条指令。接下来n行,每行表示一条指令,如上所述。M是一个正整数,不超过100000.

输出

对于每组测试数据,对于其中的每一个查询操作,都要输出一个结果。注意:每一组测试数据后要输出一个空行。

样例数据

样例输入

样例输出

1
12
generate 1
remove 2
generate 1
query
generate 7
query
generate 10
query
generate 5
query
remove 7
query

-1
6
3
2
4

STD Code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 100000
#define MAXM 100000
#define INF 0x3f3f3f3f
typedef long long int LL;
void Read(int &x)
{
x=;char c=getchar();bool flag=;
while(c<''||''<c){if(c=='-')flag=;c=getchar();}
while(''<=c&&c<=''){x=x*+c-'';c=getchar();}
if(flag)x=-x;
}
int L[MAXM*],R[MAXM*];
int len[MAXM*];
int lval[MAXM*],rval[MAXM*],minval[MAXM*];
int sz;
void updata(int x)
{
lval[x]=lval[x<<];
if(lval[x<<]==len[x<<])
lval[x]+=lval[x<<|];
rval[x]=rval[x<<|];
if(rval[x<<|]==len[x<<|])
rval[x]+=rval[x<<];
minval[x]=min(minval[x<<],minval[x<<|]);
if(rval[x<<]!=len[x<<]&&lval[x<<|]!=len[x<<|])
minval[x]=min(minval[x],rval[x<<]+lval[x<<|]);
}
void build(int l,int r,int x)
{
L[x]=l,R[x]=r;
len[x]=r-l+;
lval[x]=rval[x]=len[x];
minval[x]=INF;
if(L[x]==R[x])
return;
int mid=(l+r)>>;
build(l,mid,x<<);
build(mid+,r,x<<|);
updata(x);
}
void insert(int pos,int x)
{
if(L[x]==R[x])
{
lval[x]=rval[x]=;
minval[x]=INF;
return;
}
int mid=(L[x]+R[x])>>;
if(pos<=mid)
insert(pos,x<<);
else
insert(pos,x<<|);
updata(x);
}
void del(int pos,int x)
{
if(L[x]==R[x])
{
lval[x]=rval[x]=;
minval[x]=INF;
return;
}
int mid=(L[x]+R[x])>>;
if(pos<=mid)
del(pos,x<<);
else
del(pos,x<<|);
updata(x);
}
int query()
{
if(sz<)
return -;
else
return minval[]+;
}
bool has[MAXM+];
int main()
{
int T,n;
Read(T);
while(T--)
{
Read(n);
sz=;
build(,MAXM,);
memset(has,,sizeof(has));
char str[];
int x;
for(int i=;i<=n;++i)
{
scanf("%s",str);
if(str[]=='g')
{
Read(x);
if(!has[x])
{
has[x]=,++sz;
insert(x,);
}
}
else if(str[]=='r')
{
Read(x);
if(has[x])
{
has[x]=;
--sz;
del(x,);
}
}
else
printf("%d\n",query());
}
putchar();
}
return ;
}

题目分析

首先根据题目中涉及查询,插入,删点等操作,就可以大致判断出要用树形存储结构来做。

对于插入与删点这两个操作来说,基本就是"打板",与普通的平衡树没有什么差别。只是题目中提及“可能会删去‘不存在’的元素或插入‘存在’的元素”,最开始我没怎么在意,觉得只要在Delete函数与Insert函数里面修改一下判断条件就行了,后来却始终没有成功,调了足足有40多分钟(也就是这里耽误了太多时间)——后来发现问题在于对树的高度的更新存在问题:只要进行插入或删除操作就会更改平衡树的高度,而这显然是错误的。 后来才“迫不得已”用了一个“蠢办法”,就是设置一个bool型的has数组,去判断一个值是否存储在树中,来规避重复加/删点的问题。(当然,这个方法在最后被证明是正解)

对于查询操作,当时其实并不觉得写起来有多大的困难:在updata函数里面顺带加一个判断去更新minval数组就行了。

球星(star.cpp)

题目描述

给出球星们的能力值、年份、名字,有很多个查询,每个查询给出一个年份的范围,求出这个范围里能力值从高到低排列的前11名球员,如果能力值相同则按年份从低到高排,如果年份仍然相同,则按名字的字典序排。如果不足11个球员,就用XXX代替输出凑够11行。

输入

输入数据:
第一行包含1个整数N(1<=N<=50000),表示球星的总数,接下来N行,每行描述了1个球星(year,name,ability)。0<=year<=1000000000,name不超过15个字母,0<=ability<=1000000000.
假设没有两个人的名字相同。接下来有一个整数R,表示有R个查询。接下来R行,每行描述了一个产寻,每个查询包含2个整数(x,y),表示从第x年到第y年。(0<=x<=y<=1000000000)

输出

输出数据:对于每组数据,按上面描述的顺序输出最靠前的11个球员的名字,每个球员占一行。如果不足11行,则用XXX代替,凑够11行。每组数据后都有一个空行。

样例数据

样例输入

样例输出

5
1 a 1
2 b 2
2 c 6
5 e 50
5 d 50
2
1 2
5 5
c
b
a
XXX
XXX
XXX
XXX
XXX
XXX
XXX
XXX d
e
XXX
XXX
XXX
XXX
XXX
XXX
XXX
XXX
XXX

STD Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define maxn 50000
using namespace std;
struct node
{
int l,r;
int f[];
}tree[*maxn+];
int f[];
struct d
{
int y,a;
char n[];
bool operator <(const d &b)const
{
if(a==b.a)
{
if(y==b.y)
{
int len=max(strlen(n),strlen(b.n));
for(int i=;i<len;++i)
{
if(n[i]==b.n[i]) continue;
return n[i]>b.n[i];
}
}
return y>b.y;
}
return a<b.a;
}
}p[maxn+];
int n;
bool cmp(const d &a,const d &b)
{
return a.y<b.y;
}
void uptree(int i)
{
int lson=i<<,rson=(i<<)|;
int cl=,cr=,c=;
while((tree[lson].f[cl]||tree[rson].f[cr])&&c<)
{
if(!tree[lson].f[cl])
{
tree[i].f[c]=tree[rson].f[cr];
c++;cr++;
}
else if(!tree[rson].f[cr])
{
tree[i].f[c]=tree[lson].f[cl];
c++;cl++;
}
else if(p[tree[lson].f[cl]]<p[tree[rson].f[cr]])
{
tree[i].f[c]=tree[rson].f[cr];
c++;cr++;
}
else
{
tree[i].f[c]=tree[lson].f[cl];
c++;cl++;
}
}
return;
}
void Build_tree(int i,int l,int r)
{
tree[i].l=l;
tree[i].r=r;
if(l==r)
{
tree[i].f[]=l;
return;
}
int m=(l+r)>>;
Build_tree(i<<,l,m);
Build_tree((i<<)|,m+,r);
uptree(i);
}
void Ask(int i,int l,int r)
{
if(tree[i].l>r||tree[i].r<l) return;
if(l<=tree[i].l&&r>=tree[i].r)
{
int tf[];
memcpy(tf,f,sizeof f);
memset(f,,sizeof f);
int c1=,c2=,c=;
while((tf[c1]||tree[i].f[c2])&&c<)
{
if(!tf[c1])
{
f[c]=tree[i].f[c2];
c++;c2++;
}
else if(!tree[i].f[c2])
{
f[c]=tf[c1];
c++;c1++;
}
else if(p[tf[c1]]<p[tree[i].f[c2]])
{
f[c]=tree[i].f[c2];
c++;c2++;
}
else
{
f[c]=tf[c1];
c++;c1++;
}
}
return;
}
Ask(i<<,l,r);
Ask((i<<)|,l,r);
return;
}
int Find(int i,bool flag)
{
int L=,R=n;
if(!flag)
{
while(L<R)
{
int M=(L+R)>>;
if(p[M].y<i) L=M+;
else R=M;
}
return L;
}
else
{
while(L<R)
{
int M=(L+R+)>>;
if(p[M].y>i) R=M-;
else L=M;
}
return L;
}
}
int main()
{
p[].a=-;
while(cin>>n)
{
for(int i=;i<=n;++i)
scanf("%d%s%d",&p[i].y,p[i].n,&p[i].a);
sort(p+,p+n+,cmp);
Build_tree(,,n);
int q;
cin>>q;
for(int i=;i<=q;++i)
{
int l,r;
scanf("%d%d",&l,&r);
l=Find(l,);
r=Find(r,);
Ask(,l,r);
for(int j=;j<;++j)
{
if(f[j])
printf("%s\n",p[f[j]].n);
else printf("XXX\n");
}
if(i!=q) printf("\n");
memset(f,,sizeof f);
}
memset(tree,,sizeof tree);
}
return ;
}

题目分析

刚看到这道题的时候,唯一的反应就是“EXM?”实在是看不懂应该用那种算法好不好?想了想,觉得既然每个节点包含了那么多种信息,我就写个线段树+Splay好了,于是乎......写到一半发现自己写得思路已经不知所踪,那棵树呀就在转呀转呀......到了考试最后,我绝望的打了一个暴力,安慰自己:”至少,根据经验,至少能水个30分吧......“  测评时,发现竟只有一个数据点——是的,超级大数据,果断爆零。

下来发现,似乎并没有自己想的那么复杂,用一个线段树+结构体排序,或是一个线段树+优先队列就行了。也就是说,对于线段树中的每一个节点,都塞一个排了序的数组(优先队列也是可以的)进去,维护一下,这道题就可以解决啦。(在上面的代码中我用的是结构体)

跳跃(jump.cpp)

事情出奇的顺利,自从高考研讨会过后,z 同学专心准备 noip2010 。可能是被 z 同学的 潇洒、帅气、阳关所吸引,zn 主动约到了 z 同学,就这样,zn 与 z 同学走到了一起~!那是 一次放假,众所周知,hz 的放假,对于不回家的同学就是能走出封闭的 hz 大门好好玩上3 个小时。Zn 刚与 z 同学吃完 kfc,他们来到了衡水唯一还算比较浪漫的地方(貌似叫什么人 民公园吧,ms 了~~)。

题目描述

公园中有许多木桩,每个木桩都有一个高度,活泼的小 z 同学喜欢从一个木桩跳到另 一个木桩上,zn 说太危险了,于是 z 同学让 zn 算出每一次跳跃的危险系数。小 z 每一次跳 跃的范围是一个 k*k 的矩形,危险系数为这个矩形内最高的木桩高度减去最小的。身为 oier, 你能比学数奥的 zn 算的快吗?

输入

第一行三个整数 n(木桩为 n*n 的矩阵)、k、b(小 zz 准备跳跃的次数) 接下来为 n*n 的矩阵,描述木桩的高度

接下来 b 行;每行两个整数 x,y(表示 z 同学跳跃的范围的左上角为第 x 行第 y 列), 保证跳跃范围不超过矩阵的范围

样例数据

样例输入

样例输出

5 3 1

5 1 2 6 3

1 3 5 2 7

7 2 4 6 1

9 9 8 6 5

0 6 9 3 9

1 2

5

数据范围

对于30%的数据

0<k<=n<=250 0<b<=100

对于100%的数据

0<k<-n<=250 0<b<=1000 000

STD Code

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int f[][][];
int g[][][];
int N,M,K;
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
int log_2(int n){
int t=;
while (( << (t+))<n) t++;
return t;
}
int main(){
memset(f,,sizeof(f));
memset(g,,sizeof(g));
scanf("%d%d%d",&N,&M,&K);
for (int i=;i<=N;i++){
for (int j=;j<=N;j++){
scanf("%d",&f[i][j][]);
g[i][j][]=f[i][j][];
}
}
int w=log_2(M);
for (int k=;k<=w;k++){
for (int i=;i<=N;i++){
for (int j=;j<=N;j++){
if (i+( << k)-<=N && j+( << k)-<=N){
f[i][j][k]=min(f[i][j][k-],f[i+( << (k-))][j][k-]);
f[i][j][k]=min(f[i][j][k],f[i][j+( << (k-))][k-]);
f[i][j][k]=min(f[i][j][k],f[i+( << (k-))][j+( << (k-))][k-]);
g[i][j][k]=max(g[i][j][k-],g[i+( << (k-))][j][k-]);
g[i][j][k]=max(g[i][j][k],g[i][j+( << (k-))][k-]);
g[i][j][k]=max(g[i][j][k],g[i+( << (k-))][j+( << (k-))][k-]);
}
}
}
}
for (int t=;t<=K;t++){
int i,j;
scanf("%d%d",&i,&j);
int t1=i+M-;
int t2=j+M-;
int mi,ma;
mi=min(f[i][j][w],f[t1-( << w)+][t2-( << w)+][w]);
mi=min(mi,f[i][t2-( << w)+][w]);
mi=min(mi,f[t1-( << w)+][j][w]);
ma=max(g[i][j][w],g[t1-( << w)+][t2-( << w)+][w]);
ma=max(ma,g[i][t2-( << w)+][w]);
ma=max(ma,g[t1-( << w)+][j][w]);
printf("%d\n",ma-mi);
}
return ;
}

题目分析

“最大的”减去“最小的”,这不是一个区间求最值的RMQ问题吗?建一个线段树不就行了?再仔细一看,“n*n的矩阵”,Oh No,这明摆着是要你写一个树套树(矩形树)嘛! 由于此思路的代码非常“绞”,再加上时间不够,最后果断放弃去写第二题的暴力了。

下来后,经过两天的冥思苦想,我终于想出了“还算好写”的矩形树代码,将大矩阵分解成为多个边长为2的小正方形矩阵(即2^k*2^k),在这些小矩阵中做一个RMQ问题求出最值,在随后的数据中,每输入一个矩形,就进行一次“分割为小矩形”的操作,直接比较求最值,交上去,令人感动的AC!

Time:2017-03-25

[SinGuLaRiTy] 树形存储结构阶段性测试的更多相关文章

  1. 随心测试_数据库_003 <数据库存储结构>

    接上篇:了解了_数据库系统组成,继续理解必备知识点:数据库存储_逻辑结构 快速理解 数据存储结构:数据库系统_数据库_表 1. 理解什么是数据库 数据库发展:大致由 人工管理.文件系统.数据库系统(高 ...

  2. SQL Server 表和索引存储结构

    在上一篇文章中,我们介绍了SQL Server数据文件的页面类型,系统通过96个字节的头部信息和系统表从逻辑层面上将表的存储结构管理起来,具体到表的存储结构上,SQL Server引入对象.分区.堆或 ...

  3. 《Linux就该这么学》培训笔记_ch06_存储结构与磁盘划分

    <Linux就该这么学>培训笔记_ch06_存储结构与磁盘划分 文章最后会post上书本的笔记照片. 文章主要内容: Linux系统的文件存储结构(FHS标准) 物理设备命名规则(udev ...

  4. Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构

    Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构 1. 索引的分类1 1.1. 按照存储结构划分btree,hash,bitmap,fulltext1 1.2. 索引的类型  按查找 ...

  5. 仿Redis用来作前端浏览器的数据存储结构

    用js写了一个类似redis存储结构的类库,目前只有的存储类型只有hash.set两个, 还没测试过性能,欢迎各位猿友能够帮我指出程序代码的缺陷, 后期有时间会完善其他几个类型的存储结构. /**** ...

  6. 队列的存储结构和常见操作(c 语言实现)

    一.队列(queue) 队列和栈一样,在实际程序的算法设计和计算机一些其他分支里,都有很多重要的应用,比如计算机操作系统对进程 or 作业的优先级调度算法,对离散事件的模拟算法,还有计算机主机和外部设 ...

  7. js数据结构与算法存储结构

    数据结构(程序设计=数据结构+算法) 数据结构就是关系,没错,就是数据元素相互之间存在的一种或多种特定关系的集合. 传统上,我们把数据结构分为逻辑结构和物理结构. 逻辑结构:是指数据对象中数据元素之间 ...

  8. (续)一个demo弄清楚位图在内存中的存储结构

    本来续---数字图像处理之位图在计算机中的存储结构一文,通过参考别人的代码,进行修改和测试终于成功运行. 该实例未使用任何API和相关类,相信如果对此实例能够完全理解那么将有进一步进行数字图像处理的能 ...

  9. [置顶] ※数据结构※→☆线性表结构(queue)☆============优先队列 链式存储结构(queue priority list)(十二)

    优先队列(priority queue) 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有 ...

随机推荐

  1. 解决 Windows instance 时间不同步问题 - 每天5分钟玩转 OpenStack(153)

    这是 OpenStack 实施经验分享系列的第 3 篇. 问题描述 通过上一节部署出来的 Windows instance 有时候会发现操作系统时间总是慢 8 个小时,即使手工调整好时间和时区,下次 ...

  2. phpcmsV9静态页面替换动态步骤

    1.先在www目录下找到 phpcms + install_package + phpcms + templates在templates 文件夹里创建个自己的文件夹我弄得是 ceshi 文件夹,在 c ...

  3. devexpress实现单元格根据条件显示不同的样式(颜色、字体、对齐方式,大小等)

    1.devexpress控件库之所以被大家所喜爱,是因为它将许多常用的东西都封装成了属性.可以通过一些简单的配置,将以前某些需要大篇幅代码才可实现的效果展示出来.这里是一个实现了将[第二列数据在表格0 ...

  4. .Net程序员学用Oracle系列(18):PLSQL Developer 攻略

    1.功能说明及使用技巧 1.1.对象浏览器 1.2.SQL 窗口 1.3.测试窗口 1.4.命令窗口 1.5.图表窗口 1.6.报告窗口 1.7.右键菜单 1.8.快速登录技巧 1.9.其它 2.总结 ...

  5. 安居客Android项目架构演进

    入职安居客三年从工程师到Team Leader,见证了Android团队一路走来的发展历程.因此有心将这些记录下来与大家分享,也算是对自己三年来一部分工作的总结.希望对大家有所帮助,更希望能得到大家宝 ...

  6. iOS开发学习路径的一些建议

    结合自己情况聊下iOS学习建议,这里不讲大道理,说说具体怎么做.欢迎大家拍砖. 1.第一点要求 ,能比较顺畅的阅读官方的文档 如果你连官方的文档读起来都非常困难,那你还谈什么提高和进阶,咱们学习iOS ...

  7. HTML5 File接口(在web页面上使用文件)

    File接口提供了与文件相关的信息,并且运行JavaScript在web页面上去访问文件中的内容. File对象来自于用户使用input标签选择文件返回的FileList对象,来自于拖放操作的Data ...

  8. Oracle 字符集设置

    因为装Linux系统时选择的是英文版,所以当需要测试中文数据库时会出现乱码,这里记录一下我修改字符集的操作. 一些命令: 1.查看sqlplus客户编码: $ echo  $NLS_LANG 2.查看 ...

  9. selenium7种元素识别

    我们以百度主页搜索框为例:= <input autocomplete="off" maxlength="255" value="" c ...

  10. nodejs学习一

    总觉得一个前端,不懂得一点后端的服务,弱弱的没有存在感,所以利用现在好好 学学有关nodejs 首先是windows上进行nodejs的全局安装 32 位安装包下载地址 : https://nodej ...