洛谷p1160 双向链表

本文介绍了一种使用双向链表解决学生排队问题的高效算法。该算法通过维护两个指向链表节点的指针,实现了学生的快速插入操作,解决了大规模数据下的效率问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:
一个学校里老师要将班上N个同学排成一列,同学被编号为1~N,他采取如下的方法:
1.先将1号同学安排进队列,这时队列中只有他一个人;
2.2~N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1~i-1中某位同学(即之前已经入列的同学)的左边或右边;
3.从队列中去掉M(M
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
分析:由于数据较大,(对于100%的数据,有N,M≤100000)所以如果只是普通的插入调整,时间会达到O(N^2+MN),所以普通的算法就不行了,我们应该用双向链表left【i】表示i左边的元素,right【i】表示j右边的元素。然后插入是只需要改变一下左右两边指针(如果不懂,可以看我的代码实现)。
 关键代码:
  voidinsert_right(int a,int b)
{
_left[_right[b]]=a;
_right[a]=_right[b];
_right[b]=a;
_left[a]=b;
}

void insert_left(int a,intb)
{
if(b==head)
 head=a;
_right[_left[b]]=a;
_left[a]=_left[b];
_left[b]=a;
_right[a]=b;
}

//以上是从左添加和从右添加

整体代码:
#include
#include
#include
#include
using namespace std;
//对于100%的数据,有N, M≤100000。
int _left[100001],_right[100001];
bool delet[100001];
int n,m;
int head;
void insert_right(int a,int b)
{
_left[_right[b]]=a;
_right[a]=_right[b];
_right[b]=a;
_left[a]=b;
}

void insert_left(int a,int b)
{
if(b==head)
 head=a;
_right[_left[b]]=a;
_left[a]=_left[b];
_left[b]=a;
_right[a]=b;
}


int main()
{
int i,j,k,l;
    scanf("%d",&n);
 head=1;
 for(i=2;i<=n;i++)
   {
 scanf("%d%d",&k,&l);
    if(l==0)
    insert_left(i,k);
 else if(l==1)
    insert_right(i,k);
j=head; 
scanf("%d",&m);
for(i=1;i<=m;i++)
 {
  scanf("%d",&k);
  delet[k]=true;
   if(k==head)
     j=_left[head];
 }
 
    while(j!=0)
      {
        if(_left[j]==0)
         break;
j=_left[j];
  }

    while(j!=0)
      {
       if(!delet[j])
         printf("%d ",j);
       j=_right[j];
  }
//其实我也不知道怎么会这样,一开始从left输出顺序刚好反掉,估计应该是搞反了= =
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值