【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. c++编程思想(一)--对象导言

    回过头来看c++编程思想第一章,虽然只是对c++知识的一个总结,并没有实质性知识点,但是收获还是蛮多的! 下面感觉是让自己茅塞顿开的说法,虽然含义并不是很准确,但是很形象(自己的语言): 1.类描述了 ...

  2. C#有关虚方法要知道的知识点:

    虚方法:这个方法其实就是为了重写方法而存在的(在声明中包含virtual关键字),否则没感觉到它存在的意义. 其一:因为要重写所以它的访问类型如果为private则毫无意义阻碍了重写动作的进行也就是它 ...

  3. Unity编程标准导引-3.3 Transform

    本文为博主原创文章,欢迎转载.请保留博主链接http://blog.csdn.net/andrewfan 每个游戏对象(GameObject),其存在于游戏世界,都有一个位置.朝向.大小等基本定位信息 ...

  4. Ubuntu下搭建FTP服务器

    Ubuntu下搭建FTP服务器 我装的服务器系统是Ubuntu 12.04 LTS,FTP软件当然是选择大名鼎鼎的vsftpd(very secure FTP daemon), 用系统自带的FTP还好 ...

  5. A manager is becoming more and more popular in China

    A manager is becoming more and more popular in China; many people want to possess a position like th ...

  6. 杭电2000——ASCII码排序

    /* ASCII码排序 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tota ...

  7. 配置FindBugs和常见FindBugs错误

    配置FindBugs: 在这里可以对FindBugs规则等进行详细设置. 选择你的项目,右键 => Properties => FindBugs => 1 Run Automatic ...

  8. iOS arc下控制某一文件为非arc

    选中文件加上编译参数 -fno-objc-arc即可.

  9. 关于NoClassDefFoundError和ClassNotFoundException异常

    java.lang.NoClassDefFoundError 和 java.lang.ClassNotFoundException 都是 Java 语言定义的标准异常.从异常类的名称看似乎都跟类的定义 ...

  10. 基于react+react-router+redux+socket.io+koa开发一个聊天室

    最近练手开发了一个项目,是一个聊天室应用.项目虽不大,但是使用到了react, react-router, redux, socket.io,后端开发使用了koa,算是一个比较综合性的案例,很多概念和 ...