洛谷第三題
題目描述
一個學校里老師要將班上NN個同學排成一列,同學被編號為1\sim N1∼N,他採取如下的方法:
-
先將11號同學安排進佇列,這時佇列中只有他一個人;
-
2-N2−N號同學依次入列,編號為i的同學入列方式為:老師指定編號為i的同學站在編號為1\sim (i -1)1∼(i−1)中某位同學(即之前已經入列的同學)的左邊或右邊;
-
從佇列中去掉M(M<N)M(M<N)個同學,其他同學位置順序不變。
在所有同學按照上述方法佇列排列完畢後,老師想知道從左到右所有同學的編號。
輸入格式
第11行為一個正整數NN,表示了有NN個同學。
第2-N2−N行,第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個空格隔開的正整數,表示了佇列從左到右所有同學的編號,行末換行且無空格。
輸入輸出樣例
輸入 #14 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≤10N≤10;
對於40\%40%的資料,有N≤1000N≤1000;
對於100\%100%的資料,有N, M≤100000N,M≤100000。
解題思路:
我們可以用連結串列。插入每一個同學的時候,就把他左右兩邊的同學更新掉;
刪除同學時,先把這個同學賦為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;
}