hdu 5592 ZYB's Premutation (线段树+二分查找)

链接: http://acm.hdu.edu.cn/showproblem.php?pid=5592

Problem Description
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.
1T5,1N50000
 

 

Output
For each testcase,print the ans.
 

 

Sample Input
1
3
0 1 2
 

 

Sample Output
3 1 2

 

   思路:对于每个位置i,a[i]-a[i-1]就是它前面比它大的数,这样就能知道它是从1到i中第几大的数了。从第n个位开始找,每找到一个数给它标记掉。在线段树中存没标记的数,用二分查找数的大小。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 struct st
 6 {
 7     int l,r;
 8     int sum;
 9 };
10 st tree[500005];
11 void build(int l,int r,int p)
12 {
13     tree[p].l=l;
14     tree[p].r=r;
15     if (l==r)
16     {
17         tree[p].sum=1;
18         return ;
19     }
20     int tem=(l+r)/2;
21     build(l,tem,p*2);
22     build(tem+1,r,p*2+1);
23     tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
24 }
25 int find(int l,int r,int p)
26 {
27     if (tree[p].l>=l&&tree[p].r<=r) return tree[p].sum;
28     int tem=(tree[p].l+tree[p].r)/2;
29     if (l>tem) return find(l,r,p*2+1);
30     else if (r<=tem) return find(l,r,p*2);
31     return find(l,tem,p*2)+find(tem+1,r,p*2+1);
32 }
33 void un(int x,int p)
34 {
35     if (tree[p].l==tree[p].r)
36     {
37         tree[p].sum=0;
38         return ;
39     }
40     if (tree[p*2].r>=x) un(x,p*2);
41     else un(x,p*2+1);
42     tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
43 }
44 int main()
45 {
46     int t,n,A[50005],a[50005],v[50005];
47     int i,j,b,c,l,r,s;
48     scanf("%d",&t);
49     while (t--)
50     {
51         scanf("%d",&n);
52         memset(v,0,sizeof(v));
53         for (i=1;i<=n;i++) scanf("%d",&A[i]);
54         build(1,n,1);
55         for (i=n;i>1;i--)
56         {
57             b=i-(A[i]-A[i-1]);
58             l=b;
59             r=n;
60             while (l<=r)
61             {
62                 c=(l+r)/2;
63                 s=find(1,c,1);
64                 if (s==b&&!v[c]) break;
65                 if (s<b) l=c+1;
66                 else r=c-1;
67             }
68             a[i]=c;
69             v[c]=1;
70             un(c,1);
71         }
72         for (i=1;i<=n;i++)
73         {
74             if (!v[i])
75             {
76                 a[1]=i;
77                 break;
78             }
79         }
80         for (i=1;i<n;i++) printf("%d ",a[i]);
81         printf("%d\n",a[i]);
82     }
83 }

 

          

转载于:https://www.cnblogs.com/pblr/p/5023380.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值