SPOJ

题目链接:

https://vjudge.net/problem/SPOJ-ORDERS

题目大意:

根据每个数字的逆序对求出原数组

解题思路:

举个例子:
n = 5
a[ n ] = { 0, 1, 2, 0, 1 };
对于第5个士兵,s[ 5 ] = { 1, 2, 3, 4, 5 };
而与它对应的a[ 4 ] = 1,也就是说在他左边的士兵里,有1个比他小,他在他左边的士兵里排第四,故s[5]里第四小的排名就是他的,对应4
对于第4个士兵,s[ 4 ] = { 1, 2, 3, 5 };没有4表示第四小的排名已经被占
a[ 3 ] = 0, 也就是说他左边的士兵都比他等级高,他的排名就最大,故s[4]里最大的事5,就是他的排名
对于第3个士兵,s[ 3 ] = { 1, 2, 3 };
a[ 2 ] = 2, 表示第 3 个士兵左边的两个士兵等级都比他低,故取s[3]里最小的--1
对于第2个士兵,s[ 2 ] = { 2, 3 };
a[ 1 ] = 1, 表示第 2 个士兵左边的一个士兵等级比他低,故取s[2]里最小的--2
对于第1个士兵,s[ 1 ] = { 3 };
显然第一个士兵排名为3


故解题步骤为:


将1,2,3,...,n添加到集合s里
倒着处理每个士兵:
    1.找到s里第a[i]大的数k,赋值给r[i],为i士兵的排名
    2.将s里的k剔除

 1 #include<bits/stdc++.h>
 2 #define lowbit(i) (i & (-i))
 3 using namespace std;
 4 const int maxn = 1000005;
 5 int a[maxn];
 6 int tree[maxn], n;
 7 int ans[maxn];
 8 void add(int x, int d)
 9 {
10     while(x <= n)
11         tree[x] += d, x += lowbit(x);
12 }
13 int sum(int x)
14 {
15     int ans = 0;
16     while(x)
17         ans += tree[x], x -= lowbit(x);
18     return ans;
19 }
20 int Find(int x)
21 {
22     int l = 1, r = n;
23     while(l < r)
24     {
25         int mid = (l + r) / 2;
26         if(sum(mid) >= x)
27             r = mid;
28         else l = mid + 1;
29     }
30     return r;
31 }
32 int main()
33 {
34     int T;
35     scanf("%d", &T);
36     while(T--)
37     {
38         memset(tree, 0, sizeof(tree));
39         scanf("%d", &n);
40         for(int i = 1; i <= n; i++)add(i, 1), scanf("%d", &a[i]);
41         for(int i = n; i >= 1; i--)
42             ans[i] = Find(i - a[i]), add(ans[i], -1);
43         printf("%d", ans[1]);
44         for(int i = 2; i <= n; i++)
45             printf(" %d", ans[i]);
46         puts("");
47     }
48     return 0;
49 }
原文地址:https://www.cnblogs.com/fzl194/p/8964581.html