此题也比较简单,也是一个很经典的序列问题,不过想AC,还是不是那么容易滴
这道题要用链表来做,一开始我写的是动态链表,自己造轮子,写了一半代码接近两百行,果断放弃了,还是用静态的链表比较实在,考场上绝对不会有那么多时间给你去写动态的链表
这道题首先要控制好时间复杂度,数据量还是挺大的,如果用一般的数组做法肯定会TL,所以只能制取,我们搞个结构体,里面有左右成员L,R,分别记录这个结构体元素左边的那个序列号和右边的那个序列号
struct Node
{
int L,R;
};
Node a[100000];a[0].left=-1,a[0].right=1,a[1].left=0,a[1].right=-1
** 初始化完毕后:我们尝试插入一个元素2,加入插入1的左边**
插入后有:a[2].right=1,a[a[1].left].right=2,a[2].left=a[1].left,a[1].left=2
插入也很简单,画画图就可以搞清楚了,这里有点难以理解的地方是a[i].left,a[i].right存储的是当前序列号为i的左边的序列号和右边的序列号,这样我们就可以从a[0].right开始遍历,直到a[i].right=-1为止,就算走到头了。
删除就更简单了,只需要使得被删除元素左边的指针指向被删除元素右边的指针,被删除右边的指针指向被删除左边的指针,然后将被删除的左右指针全部设置为-1
例如a0 a1 a2(a0本身并没有实际意义)
我们删除a1,a[a[1].left].right=a[1].right,a[a[1].right].left=a[1].left,a[1].left=-1,a[1].right=-1
为了避免重复删除,我们每次删除前要进行依次判断,如果被删除的左指针是-1,那么我们可以直接返回,证明其之前就被删除过了,但是不能用右指针来判断,因为被删除的可能是最后一个元素,其右指针就是-1
** 下面是AC代码~**
#include <iostream>
#define Max 100009
using namespace std;
struct Node
{
int L,R;
};
Node a[Max];
void insert_left(int i,int k); //将i插入k号的左边
void insert_right(int i,int k); // 将i号位插入k号位的右边
void shanchu(int val) ;//删除号码为val的节点
void print();
int main()
{
int N;
cin>>N;
int k,p,M;
for(int i=0;i<=N;i++)
{
a[i].L=a[i].R=-1;
}
a[1].L=0;
a[1].R=-1;
a[0].R=1;
for(int i=2;i<=N;i++)
{
cin>>k>>p;
if(!p) //左边插入
{
insert_left(i,k);
}
else //右边插入
{
insert_right(i,k);
}
}
cin>>M;
int val;
for(int i=1;i<=M;i++)
{
cin>>val;
shanchu(val);
}
print();
return 0;
}
void insert_left(int i,int k) //将i插入k号的左边
{
a[i].R=k; //i号的右边是k号
a[a[k].L].R=i;//k号左边的同学的右边是插入后的i号
a[i].L=a[k].L;//将i号的左边设置位k号的左边
a[k].L=i;//k号位的左边设置位i号
}
void insert_right(int i,int k) // 将i号位插入k号位的右边
{
a[i].R=a[k].R; //i号位的右边设置为k号位的右边
a[a[k].R].L=i;//k号位右边的左边的位置设置为 i号位
a[i].L=k;
a[k].R=i;
}
void shanchu(int val) //删除号码为val的节点
{
if(a[val].L==-1) //如果左边的是-1那么是已经删除过了的.
{
return ;
}
a[a[val].L].R=a[val].R;
a[a[val].R].L=a[val].L;
a[val].L=a[val].R=-1;
}
void print()
{
int x=a[0].R;
while(x!=-1)
{
cout<<x<<" ";
x=a[x].R;
}
}