1. 程式人生 > 其它 >洛谷第三題

洛谷第三題

題目描述

一個學校里老師要將班上NN個同學排成一列,同學被編號為1\sim N1N,他採取如下的方法:

  1. 先將11號同學安排進佇列,這時佇列中只有他一個人;

  2. 2-N2N號同學依次入列,編號為i的同學入列方式為:老師指定編號為i的同學站在編號為1\sim (i -1)1(i1)中某位同學(即之前已經入列的同學)的左邊或右邊;

  3. 從佇列中去掉M(M<N)M(M<N)個同學,其他同學位置順序不變。

在所有同學按照上述方法佇列排列完畢後,老師想知道從左到右所有同學的編號。

輸入格式

11行為一個正整數NN,表示了有NN個同學。

2-N2N行,第ii行包含兩個整數k,pk,p,其中kk為小於ii的正整數,pp為00或者11。若pp為00,則表示將ii號同學插入到kk號同學的左邊,pp為11則表示插入到右邊。

N+1N+1行為一個正整數MM,表示去掉的同學數目。

接下來MM行,每行一個正整數xx,表示將xx號同學從佇列中移去,如果xx號同學已經不在佇列中則忽略這一條指令。

輸出格式

11行,包含最多NN個空格隔開的正整數,表示了佇列從左到右所有同學的編號,行末換行且無空格。

輸入輸出樣例

輸入 #1
4
1 0
2 1
1 0
2
3
3
輸出 #1
2 4 1

說明/提示

樣例解釋:

將同學22插入至同學11左邊,此時佇列為:

2 121

將同學33插入至同學22右邊,此時佇列為:

2 3 1231

將同學44插入至同學11左邊,此時佇列為:

2 3 4 12341

將同學33從佇列中移出,此時佇列為:

2 4 1241

同學33已經不在佇列中,忽略最後一條指令

最終佇列:

2 4 1241

資料範圍

對於20\%20%的資料,有N≤10N10;

對於40\%40%的資料,有N≤1000N1000;

對於100\%100%的資料,有N, M≤100000N,M100000。

 

 

解題思路:

我們可以用連結串列。插入每一個同學的時候,就把他左右兩邊的同學更新掉;

刪除同學時,先把這個同學賦為0,再把他左邊的同學連上右邊的同學;

最後找到排在最左邊的同學,挨個輸出。

 

具體程式碼;

#include<cstdio>
#include<cstring>
int a[100010][3],n,m;
//a[i][2]表示學號為i的同學右邊同學的學號
//a[i][3]表示學號為i的同學左邊同學的學號
int main()
{
    scanf("%d",&n); int j=1;
    memset(a,0,sizeof(a)); a[1][1]=1;
    for(int i=2;i<=n;i++)
    {
        int x,y; scanf("%d %d",&x,&y);
        a[i][1]=i;
        if(y==0)
        //插入左邊
        { 
            a[a[x][3]][2]=i; a[i][2]=x;
            a[i][3]=a[x][3]; a[x][3]=i;
            if(x==j) j=i;
            //比較麻煩,要改連結串列
        }
        else
        //插入右邊
        {
            a[i][2]=a[x][2]; a[a[x][2]][3]=i;
            a[x][2]=i; a[i][3]=x;
        }
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int x; scanf("%d",&x);
        if(a[x][1]!=0)
        //該同學還在 
        {
            a[x][1]=0;
            //踢掉……(好可憐) 
            a[a[x][3]][2]=a[x][2];
            a[a[x][2]][3]=a[x][3];
            n--;
            if(x==j) j=a[x][3];
        }
    }
    int i=1,x=j;
    while(i<=n)
    {
        printf("%d ",a[x][1]);
        x=a[x][2]; i++;
    }
    return 0;
}