这次的数据类型但凡过了CSP的IOer都知道。
P1160 队列安排
题目大意:
一个闲着没事干的老师,让
n
(
1
≤
n
≤
100000
)
n(1\le n\le 100000)
n(1≤n≤100000)个同学排成一列,他们被依次编号为
1
∼
n
1\sim n
1∼n,老师先让一个
1
1
1号同学进入队列(此时队列中只有
1
1
1号同学),然后再让
2
∼
n
2\sim n
2∼n号同学依次进入队列,老师会让
i
i
i号同学站在
1
∼
(
i
−
1
)
1\sim(i-1)
1∼(i−1)号同学的左边或是右边,待所有同学进入队列后,老师会让
m
(
1
≤
m
≤
n
≤
100000
)
m(1\le m\le n\le 100000)
m(1≤m≤n≤100000)位同学退出队列。
老师想知道,等他的这一顿猛如虎的操作结束后,他想知道目前队列中的学生从左到右的编号依次是多少。
解题思路&代码实现:
这道题要求我们使用能随心所欲的插入、删除元素,普通的数组显然我发做到这一点,于是,就把考CSP时压箱底的数据类型——链表搬出来了。
链表,这玩意不同于其他数组,其他类型的数组除了加入、去除元素的方式有些不同外,其他的都差不多,毕竟他们的存储方式都是记录自己本身的值,而链表呢?他记的是前驱(
p
r
e
pre
pre)和后继(
n
x
t
nxt
nxt),这么说把,它几下了它同桌的名字,而且记得牢牢的,但不知道自己叫啥,它查询自己的值,就得用以下两种方法:
- 问自己的前驱:“你的后继叫啥名儿?”
a[i]==a[a[i].pre].nxt;
- 问自己的后继:“你的前驱叫啥名儿?”
a[i]==a[a[i].nxt].pre;
麻烦是麻烦了点,但它有一个好处在于,可以方便的插入、删除元素,这不正好是我们需要的吗?
首先,我们得搞清楚怎么在链表里插入、删除元素。
- 插入在左边
假设原先队列里是
[
1
,
2
]
[1,2]
[1,2],我们要在
2
2
2的左边插入元素3,我们的操作分为如下步骤:
1.将
1
1
1的后继设为
3
3
3;
2.将
2
2
2的前驱设为
3
3
3;
3.将
3
3
3的前驱设为
1
1
1;
4.将
3
3
3的后继设为
2
2
2;
即
struct node{
int pre,nxt;
};
node a[5]={node(0,1),node(0,2),node(1,4),node(0,0);node(2,0)};
//链表数据为:[1,2];
int main(){
int k,i;
k=2;
i=3
int q;
q=a[k].pre;
a[q].nxt=i;
a[k].pre=i;
a[i].pre=q;
a[i].nxt=k;
//现在链表数据为[1,3,2]
}
- 插入在右边
假设原先队列里是
[
1
,
2
]
[1,2]
[1,2],我们要在
1
1
1的右边插入元素3,我们的操作分为如下步骤:
1.将
2
2
2的前驱设为
3
3
3;
2.将
1
1
1的后继设为
3
3
3;
3.将
3
3
3的后继设为
2
2
2;
4.将
3
3
3的前驱设为
1
1
1;
即
struct node{
int pre,nxt;
};
node a[5]={node(0,1),node(0,2),node(1,4),node(0,0);node(2,0)};
//链表数据为:[1,2];
int main(){
int k,i;
k=1;
i=3
int q;
q=a[k].nxt;
a[q].pre=i;
a[k].nxt=i;
a[i].nxt=q;
a[i].pre=k;
//现在链表数据为[1,3,2]
}
现在,我们知道了怎么插入,那么,删除呢?
删除的流程:
还是
[
1
,
3
,
2
]
[1,3,2]
[1,3,2]的链表,我们要删除
3
3
3,我们的操作分为以下步骤:
1.将
1
1
1的后继改成
2
2
2;(将
3
3
3的前驱的后继改成
3
3
3的后继)
2.将
2
2
2的前驱改成
1
1
1。(将
3
3
3的后继的前驱改成
3
3
3的前驱)
即
struct node{
int pre,nxt;
};
node a[5]={node(0,1),node(0,3),node(3,4),node(1,2);node(2,0)};
//链表数据为:[1,3,2];
int main(){
k=3;
a[a[k].pre].nxt=a[k].nxt;
a[a[k].nxt].pre=a[k].pre;
//现在链表数据为[1,2]
}
同时,我们还要用数组
v
v
v来记录每一位同学是否在队列里,防止误删,还要把
1
1
1号同学的前驱、后继指向不存在的同学
0
、
n
+
1
0、n+1
0、n+1。
好的,直接开码~~
#include<bits/stdc++.h>
using namespace std;
struct node{//结构体
int pre,nxt;
};
node a[100005];
bool v[100005];//v[i]表示编号为i的学生是否已出队,防止重复删除导致WA
int n,m,k,p;//n,m不会的请重新阅读本文,k表示操作位置,p表示操作类型
int main(){
cin>>n;//输入同学总数
int i;
a[1].pre=0;
a[1].nxt=n+1;//把1号同学的前驱、后继指向不存在的同学0、n+1。
for (i=2;i<=n;i++){
cin>>k>>p;
if (p==0){
int q;
q=a[k].pre;
a[q].nxt=i;
a[k].pre=i;
a[i].pre=q;
a[i].nxt=k;//在k的左边插入i
}
else{
int q;
q=a[k].nxt;
a[q].pre=i;
a[k].nxt=i;
a[i].nxt=q;
a[i].pre=k;//在k的右边插入i
}
}
cin>>m;//输入要退出队列的同学个数
for (i=1;i<=m;i++){
cin>>k;
if (v[k]){
continue;
}
a[a[k].pre].nxt=a[k].nxt;
a[a[k].nxt].pre=a[k].pre;
v[k]=1;
}
int fir=a[0].nxt;
while (fir!=n+1){
cout<<fir<<' ';
fir=a[fir].nxt;
}//输出
}
直接AC,完结撒花!
祝你AC!