板子题-插队
约瑟夫:luogu P1145
由于约瑟夫仅仅涉及到了链表的删除,所以这里换一题:
题目描述
有N个人(编号1到N)排队,一开始这N个人从1到N号顺序排队,接下来出现Q次插队,每一次为X号插入到了Y号的后面,询问最终结果。
输入
第一行两个数字,代表
N
N
N,
Q
Q
Q
接下来
Q
Q
Q行,每行两个数字
X
X
X,
Y
Y
Y代表
X
X
X号插入到了
Y
Y
Y号的后面
输出
Q Q Q次插入后的结果
样例输入
5 3
1 2
2 4
3 5
样例输出
1 4 2 5 3
提示
【样例解释】
原始数据:1 2 3 4 5
一次插队:2 1 3 4 5
两次插队:1 3 4 2 5
三次插队:1 4 2 5 3
1
≤
N
,
Q
≤
100000
1\leq N,Q\leq100000
1≤N,Q≤100000
算法理解
链表其实就是一种数据结构,链表的每一个节点可以分成两个区域,分别是数据域和指针域,数据域代表链表的数据,可以是一个变量或数组,也可以是一堆变量(结构体)。而指针域就可以分为前驱和后缀。
struct NODE{
int a;//部分OJ中,next是系统关键字,可能会导致编译错误
NODE *nex,*pre;//数据域为一个int类型的变量
};//其实不一定要用指针(我也不用)
链表的组成
这里就贴一张图吧。默认数据域有一个int类型的数字,并且带有前缀的链表。
其中尾一般就是NUUL(空指针)或者是 − 1 -1 −1。
算法实现
首先,为初赛的同学们说一下,链表和数组各有长处,没有好坏,除非拿出一道具体的题目出来。
删除
链表的删除就不想数组那么麻烦,因为指针域有很大的好处,方法如下:(双向链表)
就这样,代码如下:
a[a[x].pre].nex=a[x].nex;
a[a[x].nex].pre=a[x].pre;//删去x点
这里就不怎么需要顺序。
插入
插入就不画图了,你们应该懂,但是插入就需要顺序了,这个很重要。代码:
a[a[y].nex].pre=x;
a[x].nex=a[y].nex;
a[y].nex=x;
a[x].pre=y;
这里吧x插在y的后面。
板子题-解析
虽然从字面上来看,仅仅是插入,但是在插入之前,这个点要删除掉,所以必须要用双向链表。
代码::
#include<cstdio>
#define maxn 100039
using namespace std;
int n,T;
struct NODE{
int pre,nex;
}a[maxn];
int head,x,y,i;
int main(){
scanf("%d%d",&n,&T);
for(i=2;i<n;i++)
a[i].pre=i-1,a[i].nex=i+1;
a[1].pre=-1; a[1].nex=2;
a[n].pre=n-1; a[n].nex=1;
head=1;
while(T--){
scanf("%d%d",&x,&y);
//删去x点
if(x==head)//如果x是头
head=a[x].nex; //把头给x的后面
a[a[x].pre].nex=a[x].nex;
a[a[x].nex].pre=a[x].pre;
//插入x点
a[a[y].nex].pre=x;
a[x].nex=a[y].nex;
a[y].nex=x;
a[x].pre=y;
}
printf("%d ",head);
i=a[head].nex;
while(i!=head){
printf("%d ",i);
i=a[i].nex;
}
return 0;
}
END.