CSUOJ_小M的移动硬盘


第一次写自己的题解吐舌头希望大家多多包含。

正题:附上题目链接http://acm.csu.edu.cn/csuoj/contest/problem?cid=2157&pid=V

题目讲的是要实现对一个有序序列进行三种操作,并输出操作后的序列。

1.1 u   表示将u置于序列首

2.2 u 表示将u置于序列尾

3.3 u v 表示将u置于v后面

看到这种问题,这些操作,我当然想到的是链表

第一个思路:用了双向链表(头指针head,尾指针tail),但是提交time limit exceed.

仔细考虑之后发现由于后台给的测试数据较大,在用这种传统的指针双向链表时,由于每次操作多了一个“遍历查找”,所以超时是难以避免的。

换一个思路:用两个数组来模拟双向链表,lef[i]表示i左边的数据,righ[i]表示i右边的数据。这样一来,每次都能在O(1)的时间内找到源操作数,快速的多。而实现两个数的连接,可以用以下函数

void link(int L,int R)
{ 
  righ[L]=R;
  lef[R]=L;
}

直接附上源代码(C++)

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=300000+5;

/*这题中的用两个数组模拟双向链表的思想与操作尤为金桥
特别是对于头指针、尾指针的设置*/
int lef[maxn];
int righ[maxn];
void link(int L,int R);

int main()
{
    int T;
    int n,m;
    int order,a,b;
    cin>>T;
    while(T--)
    {
        cin>>n>>m;
        for(int i=1;i<=n+1;i++)
        {
            lef[i]=i-1;
            righ[i]=(i+1)%(n+2);
        }

        lef[0]=n+1;
        righ[0]=1;
       righ[n+1]=0;
     while(m--)
     {
     cin>>order;
       if(order==1)
       {
           cin>>a;

          link(lef[a],righ[a]);//置顶前奏

           //置顶的操作
          link(a,righ[0]);
          link(0,a);

       }
       else if(order==2)
       {
           cin>>a;
           link(lef[a],righ[a]);//至尾前奏

           //至尾操作
           //注意先后顺序
           link(lef[n+1],a);
           link(a,n+1);

       }
       else if(order==3)
       {
           cin>>a>>b;
           link(lef[a],righ[a]);
           link(a,righ[b]);
           link(b,a);

       }

    }
    int b=0;
    for(int i=1;i<n;i++)
    {
        b=righ[b];
           cout<<b<<" ";
    }
    b=righ[b];
    cout<<b<<endl;
     }
return 0;
}
void link(int L,int R)
{

    righ[L]=R;
    lef[R]=L;
}

另外解释一下为什么两个数组名没用left,right.因为本人的编译器的原因,似乎是ios_base::right已经存在关键词,具体也不懂。

哪位能解释一下,在下小白感激不尽!!

猜你喜欢

转载自blog.csdn.net/caobo_lq666/article/details/80544133