1. 程式人生 > >Buy Tickets

Buy Tickets

/*題意:有n個人,給出n個人要插入的位置與其價值,輸出最後的價值*/

/*【題解】:
    線段樹節點中儲存這一段中的空位數,然後倒序對pos插入:
    例如:  0 77
         1 51
         1 33
         2 69
  先取: 2 69  ——  ——  —69—   ——   (需要前面有3個空位才能插入)
       然後取: 1 33   ——   —33—    —69—    ——   (需要前面有2個空位才能插入)
       然後取: 1 51   ——   —33—    —69—    —51—   (需要前面有2個空位才能插入)  前面只有1個空位  故插入後面空格
  然後取: 0 77   —77—   —33—    —69—    —51—   (需要前面有1個空位才能插入)
*/

/*由於左後一個人插進來後他的位置肯定是固定的

我們就可以倒著來插,最後一個固定後,如果倒數第二個插入的序號小於當前那麼就往前插到序號上,否則往後插,往後的話序號需要減去當前這個數左邊的空位數

因為左右都是從0位置開始標記的

因此結構體裡需要維持節點左右邊的空位個數,當前插隊序號小於左邊空位插左邊,大於的話插右邊,但是需要需要減去左邊空位。。因為右邊也是從0位置開始算起的,並且

我們是倒著插,所以空位個數才是當時的需要插的位置,已經被佔的位置當時還不存在..*/


#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;

struct node
{
	int l, r, sum;
	int mark;
}dp[1000005];

int p[200005];
int v[200005];
int ans[200005];

void Create(int l, int r, int i)
{
	dp[i].l = l;
	dp[i].r = r;
	dp[i].sum = (r - l + 1);
	if (l == r)
	{
		return;
	}
	int mid = (l + r) >> 1;
	Create(l, mid, i * 2);
	Create(mid + 1, r, i * 2 + 1);
}

void Change(int a, int b, int i)//a表示空格數量,b為輸入的值,i為節點
{
	if (dp[i].l == dp[i].r)
	{
		dp[i].sum = 0;
		ans[dp[i].l] = b;
		return;
	}
	int mid = (dp[i].l + dp[i].r) / 2;
	//優先放在左邊
	if (a <= dp[i * 2].sum)//如果左邊放的下
	{
		Change(a, b, i * 2);
	}
	else//左邊放不下
		Change(a - dp[i * 2].sum, b, i * 2 + 1);
	dp[i].sum = dp[i * 2].sum + dp[i * 2 + 1].sum;
}


int main()
{
	int n;
	while (cin>>n)
	{
		Create(1, n, 1);
		for (int i = 0; i < n; i++)
		{
			scanf("%d%d", &p[i], &v[i]);
		}
		for (int i = n - 1; i >= 0; i--)
		{
			Change(p[i] + 1, v[i], 1);
		}
		for (int i = 1; i <= n; i++)
		{
			if (i != 1)
			{
				cout << " ";
			}
			cout << ans[i];
		}
		cout << endl;
	}
	return 0;
}