2021年夏季学期华清大学电子系数算oj2题解

某知名oier锐评蒟蒻的oj1题解:

话不多说,进入oj2题解:

难缠的oj 之 难缠的店长

当时读完我已经因为无良甲方的行为出离愤怒了!
但是做题还是要做!

1.建立链表

本题实际上是链表模板题,但是据学长反映,用我们在《程序设计基础》中接触的以结构体,指针构造节点的办法,并不能ac此题! 回想一下,其实我们在结构体中,存储了指向下一个节点的指针。那么,有没有其他的办法,使得我们可以记录下一个节点的位置呢? 在数组中,我们可以通过下标索引的方法快速访问指定元素。那么,也就是说,我们只要把下一节点的下标想办法存在当前节点,就可以达到与传统链表一样的功能了! 因此,我们只需要再init一个数组,用于存储下一节点的下标,就可以实现常数更优化的访问了!

但是,我们仔细读题发现,店长的要求非常混乱:不仅要添加,删除,调换,甚至要改变全序。这时候,我们发现单向的链表并不能满足题目的要求了。但这并不构成困难,我们只需再init一个数组,构成双向链表结构即可。 然后,我们按照数算老师课上的要求:先继承再添加的原则,一步一步实现题目要求的功能。

理论上,我们需要三个数组:a[i]用于存储当前节点的值,l[i]用于存储当前节点的上一节点的下标,r[i]用于存储当前节点的下一节点的下标。但是,由于本题中恰好有物体的编号从1到n,定义域等于值域,因此可以少建立一个数组,用两个数组实现链表。

2.实现题目要求的功能

2.1 添加节点

添加的物品分为,添加到右边的物体和添加到左边的物体,原理大体相同,现在以把物体添加到左边为例:
首先,为了使得我们从始至终都只有“向一个链表中添加节点”而不存在“从0到1个节点”的过程,我们先初始化两个边界节点,这里我使用了下标0和下标n+1。也就是说,这两个节点始终作为首尾节点存在着,这使得我们不用了考虑建立一个链表的问题。

int i,j,lorr;read(i),read(j),read(lorr);
if(lorr==num){l[i]=l[j],r[l[j]]=i,r[i]=j;l[j]=i;}
else if(lorr==-1){r[0]=i;r[i]=n+1;l[n+1]=i;l[i]=0;}
else{r[i]=r[j];l[r[j]]=i;l[i]=j;r[j]=i;}

如这段代码写的这样,我们在添加节点时,先把原来存在的指针(此处把下标索引称为指针了)继承下来,然后再按照情况添加新的。注意不要漏写,必须保证每个节点与左右节点都是双向的。

2.2 删除节点

删除节点与添加节点几乎同理,仍然是对l,r数组进行操作。

int ri=r[i],li=l[i];
l[ri]=li,r[li]=ri;l[i]=0;r[i]=0;

此处不进行冗余的解释。

2.3 调换操作

按照我们前两步的思维,调换节点无非就是删除两个节点,再添加两个节点。确实,对于大多数节点,这样的做法是正确的。但是,如果你要调换的两个节点正好相邻,那么,由于删除和添加操作都涉及到对相邻节点的操作,可能会出现问题。可能不会,我不知道,请自行实践。因此,对于相邻的节点,我们可以引入特判。

int i,j;read(i),read(j);
if(r[i]==j){
int li=l[i],rj=r[j];
r[li]=j,l[rj]=i,r[j]=i,l[i]=j,r[i]=rj,l[j]=li;
}
else if(r[j]==i){
int ri=r[i],lj=l[j];
r[lj]=i,l[ri]=j,r[i]=j,l[j]=i,r[j]=ri,l[i]=lj;
}
else{
int li=l[i],ri=r[i],lj=l[j],rj=r[j];
r[li]=j,l[j]=li,l[ri]=j;r[j]=ri;
r[lj]=i,l[i]=lj,l[rj]=i,r[i]=rj;
}

2.4 改变全序

看起来这一步最为丧心病狂,但是,实际上,只要我们记住当前翻转的总次数,然后按照需要的顺序输出就好了!

else if(boo==-2){num++;num=num&1;}

附上ac代码

#include<cstdio>
#include<ctype.h>
using namespace std;
int l[200005],r[200005];
inline void read(int&x){
char c,f=x=0;
while(!isdigit(c=getchar()))f=c=='-';
while(isdigit(c))x=x*10-48+c,c=getchar();
if(f)x=-x;
}
int main(){
int n,m,k,u,num=0;read(n),read(m),read(k),read(u);
r[0]=n+1;l[n+1]=0;
for(int i=1;i<=n+m+k+u;i++){
int boo;read(boo);
if(boo==1){
int i,j,lorr;read(i),read(j),read(lorr);
if(lorr==num){l[i]=l[j],r[l[j]]=i,r[i]=j;l[j]=i;}
else if(lorr==-1){r[0]=i;r[i]=n+1;l[n+1]=i;l[i]=0;}
else{r[i]=r[j];l[r[j]]=i;l[i]=j;r[j]=i;}
}
else if(!boo){
int i;read(i);
int ri=r[i],li=l[i];
l[ri]=li,r[li]=ri;l[i]=0;r[i]=0;
}
else if(boo==-1){
int i,j;read(i),read(j);
if(r[i]==j){
int li=l[i],rj=r[j];
r[li]=j,l[rj]=i,r[j]=i,l[i]=j,r[i]=rj,l[j]=li;
}
else if(r[j]==i){
int ri=r[i],lj=l[j];
r[lj]=i,l[ri]=j,r[i]=j,l[j]=i,r[j]=ri,l[i]=lj;
}
else{
int li=l[i],ri=r[i],lj=l[j],rj=r[j];
r[li]=j,l[j]=li,l[ri]=j;r[j]=ri;
r[lj]=i,l[i]=lj,l[rj]=i,r[i]=rj;
}
}
else if(boo==-2){num++;num=num&1;}
}
if(num){int i=n+1;while(l[i]){printf("%d ",l[i]);i=l[i];}}
else {int i=0;while(r[i]-n-1){printf("%d ",r[i]);i=r[i];}}
printf("-1");
}

通过快读得到了60ms的坏成绩

最新文章

  1. Android调用微信登陆、分享、支付
  2. Python~~~关键字~~~
  3. 利用Dreamweaver配置PHP服务器的站点
  4. 用Node.js开发Windows 10物联网应用
  5. Color Space: Ycc
  6. android 拉伸图片
  7. mysql - 最小缺失值查询
  8. Redhat 6环境下安装Oracle 12c的方法
  9. 收缩SQL数据库日志文件
  10. BASM遵循的规则
  11. iOS XMPP(1)
  12. [BZOJ 3894] 文理分科 【最小割】
  13. OFBiz中根据店铺获取产品可用库存的方法
  14. 13. Roman to Integer
  15. 公布一个基于 Reactor 模式的 C++ 网络库
  16. Java 集合 ArrayList和LinkedList的几种循环遍历方式及性能对比分析 [ 转载 ]
  17. 对于Hibernate的底层浅谈
  18. 快速签发 Let&#39;s Encrypt 证书指南
  19. Unable to connect to MKS;Too many scoket connect attempts;giving up
  20. You just run!

热门文章

  1. Numpy实现机器学习交叉验证的数据划分
  2. html5中常被忘记的标签,属性
  3. HTML5离线存储整理
  4. 前端面试题整理——手写bind函数
  5. DOM节点详解
  6. Android 接入腾讯IM即时通信(详细图文)
  7. 文件上传——IIS6.0解析漏洞
  8. python---括号匹配
  9. Jenkins忘记admin密码
  10. AgileConfig 1.6.0 发布 - 支持服务注册与发现