hdu 5592 ZYB's Premutation (权值线段树)

最近在线段树的世界里遨游,什么都能用线段树做,这不又一道权值线段树了么。


ZYB's Premutation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1029    Accepted Submission(s): 528

Problem Description
ZYBhdu 5592 ZYB's Premutation (权值线段树)

has a premutation Phdu 5592 ZYB's Premutation (权值线段树)

,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)hdu 5592 ZYB's Premutation (权值线段树)

is considered as a reverse log if Ahdu 5592 ZYB's Premutation (权值线段树)ihdu 5592 ZYB's Premutation (权值线段树)>Ahdu 5592 ZYB's Premutation (权值线段树)jhdu 5592 ZYB's Premutation (权值线段树)hdu 5592 ZYB's Premutation (权值线段树)

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 Nhdu 5592 ZYB's Premutation (权值线段树)

.

In the next line there are Nhdu 5592 ZYB's Premutation (权值线段树)

numbers Ahdu 5592 ZYB's Premutation (权值线段树)ihdu 5592 ZYB's Premutation (权值线段树)hdu 5592 ZYB's Premutation (权值线段树)

,describe the number of the reverse logs of each prefix,

The input is correct.

1≤T≤5hdu 5592 ZYB's Premutation (权值线段树)

,1≤N≤50000hdu 5592 ZYB's Premutation (权值线段树)

 
Output
For each testcase,print the ans.
 
Sample Input
1
3
0 1 2
 
Sample Output
3 1 2
 
 
 
 
这道题的意思就是:你知道有一个1~n的排列,但具体排列你不知道。现在给出1~n每个前缀的逆序数对数,让你还原这个排列。
想法很简单,我们将这个逆序数数列rev从后往前看。我们从最后一个位置往前逐个得出ans。对于第i个前缀和的逆序数对数rev[i],我们得出他的逆序数对数较前一个前缀和的增长量,即up=rev[i]-rev[i-1],那么在i位置前就有up个数是大于当前位置的数字的,所以该位置的数字就是剩下的这些数字里的第i-up大的数字。于是我们把1~n构建一棵权值线段树。初始化每个数字的权值都是1。然后从n~1处理。每一次都query取出第i-up大的数字作为当前位置的答案,然后update将该数字从该权值线段树删除,然后到前一个位置继续相同操作。最后就能得出这样一个正确的排列了。
 #include<cstdio>
#include<iostream>
#include<cstring>
#define clr(x) memset(x,0,sizeof(x))
using namespace std;
struct segtree
{
int l,r,val,num;
}tree[];
int n,m,rev[],ans[];
void init(int i,int l,int r);
int query(int i,int k);
void update(int i,int pos);
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
clr(rev);
clr(ans);
for(int i=;i<=n;i++)
scanf("%d",&rev[i]);
init(,,n);
for(int i=n;i>=;i--)
{
ans[i]=query(,i-(rev[i]-rev[i-]));
update(,ans[i]);
}
for(int i=;i<n;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
return ;
}
void init(int i,int l,int r)
{
tree[i].l=l;
tree[i].r=r;
tree[i].num=r-l+;
tree[i].val=r;
if(l==r)
return;
int mid=(l+r)>>;
init(i<<,l,mid);
init((i<<)|,mid+,r);
}
int query(int i,int k)
{
if(tree[i].l==tree[i].r)
return tree[i].val;
if(tree[i<<].num>=k)
return query(i<<,k);
else
return query((i<<)|,k-tree[i<<].num);
}
void update(int i,int pos)
{
tree[i].num--;
if(tree[i].l==tree[i].r)
return ;
if(pos<=tree[i<<].r)
update(i<<,pos);
else
update((i<<)|,pos);
return ;
}
上一篇:Bestcoder round #65 && hdu 5592 ZYB's Premutation 线段树


下一篇:配置免安装版JAVA1.7的环境变量