小记: 这题之前想的简单了, 后来看了样例,发现了自己想法的错误
思路:一开始便发现这题,应该反过来思考的。但是用线段树解决还是有点没想到。
方法是:从后面开始看起,这样计算完它之后,计算后面的值的时候不会影响之前计算过了的结果。相当于无后效性
对每个值 有一个 pos值,那么其所在位置至少是pos+1之后,因为pos值是从0开始的,正常的位置是从1开始的
所以,以pos值建线段树, 目的是在pos+1位置处放下当前的value,而有可能pos+1位置已经被占用了,所以要往后推
这里我们给线段树的每个节点加一个space,代表这一段还有多少个位置可以使用,因为pos+1是从1开始数起的,
所以线段树二分时,左边的空间够的话,就直接进入左边,什么都不用改,而若不够,则要进入右边,但是值要减去左边的space值,
这样求得最后的位置就必然是答案了,而当那个位置确定下来的时候,我们就应该记录下来,开个数组记录即可。
代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <map> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> using namespace std; #define mst(a,b) memset(a,b,sizeof(a)) #define REP(a,b,c) for(int a = b; a < c; ++a) #define eps 10e-8 const int MAX_ = 200010; const int N = 100010; const int INF = 0x7fffffff; struct node{ int l, r; int space; }tree[MAX_*5]; int ans[MAX_]; int a[MAX_], b[MAX_]; void build(int l, int r, int k) { if(l == r){ tree[k].l = l; tree[k].r = r; tree[k].space = 1; return ; } int mid = l + (r-l)/2; tree[k].l = l; tree[k].r = r; build(l, mid, k<<1); build(mid+1, r, (k<<1)|1); tree[k].space = tree[k<<1].space + tree[(k<<1)|1].space; } void insert(int p, int value, int k) { if(tree[k].l == tree[k].r){ tree[k].space = 0; ans[tree[k].l] = value; return ; } if(p <= tree[k<<1].space){ insert(p, value, k<<1); } else{ insert(p-tree[k<<1].space, value, (k<<1)|1); } tree[k].space = tree[k<<1].space + tree[(k<<1)|1].space; } int main(){ int n, m; while(~scanf("%d", &n)){ REP(i, 0, n){ scanf("%d%d", &a[i], &b[i]); } build(0, n-1, 1); for(int i = n-1; i > -1; --i){ insert(a[i]+1, b[i], 1); } printf("%d", ans[0]); REP(i, 1, n){ printf(" %d",ans[i]); } printf("\n"); } return 0; }