线段树 - ZYB's Premutation
ZYB has a premutation P,but he only remeber the reverse log of each prefix of the premutation,now he ask you to
restore the premutation.
Pair (i, j)(i < j) is considered as a reverse log if Ai > Aj is matched.
Input
In the first line there is the number of testcases T.
For each teatcase:
In the first line there is one number N.
In the next line there are N numbers Ai,describe the number of the reverse logs of each prefix,
The input is correct.
1 <= T <= 51,1 <= N <= 50000.
Output
For each testcase,print the ans.
Sample Input
1
3
0 1 2
Sample Output
3 1 2
----------------------------------------我是分割线^_^-------------------------------------------
又是一道线段树的题目,普通方法也可以做,只不过肯定超时了,因为用线段树进行优化之后都差点超时= =,
又是逆序数,题目意思是说给出逆序数对数的前缀和,然后让你求出原序列,查看题解后你会发现一个规律:
题目给出的Ai,可以通过与前一项相减获得第i个数在1到n的第几大蛇王位置,第i个数为A(i) - A(i-1) + 1
大,括号中的数为下标,然后通过线段树找得到这个数在剩下的为筛选出去的数中的第几大的位置。
#include<iostream>
#include<algorithm>
#include<cstring> #include<cstdio> #include<cmath> #include<string> #include<queue> #include<vector> #include<cctype> #include<set> #include<map> #include<sstream> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define INF 0x3f3f3f3f #define Int __int64 #define pii pair<int,int> const int MAXN = 55555; int sum[MAXN<<2]; int num[MAXN]; int ans[MAXN]; void PushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void Build(int l, int r, int rt) { if (l == r) { sum[rt] = 1; return ; } int m = (l + r)>>1; Build(lson); Build(rson); PushUp(rt); } void UpDate(int pos, int l, int r, int rt) { if (l == r) { sum[rt] = 0; return ; } int m = (l + r)>>1; if (pos <= m) UpDate(pos, lson); else UpDate(pos, rson); PushUp(rt); } int Query(int value, int l, int r, int rt) { if (l == r) { return r; } int ret; int m = (l + r)>>1; if (value - sum[rt<<1|1] > 0) ret = Query(value - sum[rt<<1|1], lson);/*注意理解这里,
如果第几大的位置超过右边的范围了,就去左边找*/ else ret = Query(value, rson); return ret;