HDU5592(线段树+二分)

***********************************************声明******************************************************

      原创作品,出自 “晓风残月xj” 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj)。

      由于各种原因,可能存在诸多不足,欢迎斧正!

********************************************************************************************************* 

ZYB's Premutation

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


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
 

Source
BestCoder Round #65


     本题要求根据每个位置逆序数的累计个数,还原数列。可以从后往前推,求出当前位置元素ans[i]的前面有多少元素比他大或比他小,ans[i]=log[i]-log[i-1,注意边界的处理,但时,只知道前面比他大或比他小的元素是不能准确定位元素大小的,还得知道后面比他大或比他小的元素。

1)、前面比他大或小的元素个数可以通过反向遍历O(n)求出。

2)、后面比他大或小的元素个数可以通过在某个数组中标价,然后通过二分结合某个快速求区间和的算法-线段树得出,时间复杂度O(log(N))^2

     这样一来,总的时间复杂度为O(N*log(N))  .好久没做题,在没有模板的情况下一棵线段树和二分求第一个等于某个元素的代码调试了很久,看来以后得多敲敲这类基础代码,而不是一味的堆积业务代码,哈哈。


#include
#include
#define MAXN 50000+10

int log[MAXN];
int ans[MAXN];

struct treeNode
{
	int l,r,sum;
}tree[MAXN*3];

void build(int id,int l,int r)
{
	tree[id].l=l,tree[id].r=r;
	if(l==r)
	{
		tree[id].sum=1;
		return ;
	}
	int mid=(l+r)>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}

void update(int pos,int id,int val)
{
	if(tree[id].l==tree[id].r)
	{
		tree[id].sum+=val;
		return ;
	}
	int mid=(tree[id].l+tree[id].r)>>1;
	if(pos<=mid)
	{
		update(pos,id<<1,val);
	}
	else
	{
		update(pos,id<<1|1,val);
	}
	tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}

int query(int l,int r,int id)
{
	if(tree[id].l==l&&tree[id].r==r)
	{
		return tree[id].sum;
	}
	int mid=(tree[id].l+tree[id].r)>>1;
	if(r<=mid)
	{
		return query(l,r,id<<1);
	}
	else if(l>mid)
	{
		return query(l,r,id<<1|1);
	}
	return query(l,mid,id<<1)+query(mid+1,r,id<<1|1);
}

int main()
{
	int t;
	scanf("%d",&t);
	while(--t)
	{
		memset(tree,MAXN*sizeof(int),0);
		int n;
		scanf("%d",&n);
		log[0]=0;
		for(int i=1;i<=n;++i)
		{
			scanf("%d",&log[i]);
		}
		build(1,1,n);
		for(int j=n;j>0;--j)
		{
			int tmp=j-(log[j]-log[j-1])-1;
			int l=1,r=n;
			while(l>1;
			//	printf("tmp=%d  mid=%d l=%d  r=%d\n",tmp,mid,l,r);
				if(query(l,mid,1)<=tmp)
				{
					l=mid+1;
				}
				else
				{
					r=mid;
				}
			}
			ans[j]=l;
		//	printf("%d  \n",l);
			update(ans[j],1,-1);
		}
		for(int k=1;k<=n;++k)
		{
			printf("%d ",ans[k]);
		}
		printf("\n");
	}
	return 0;
}

                           




你可能感兴趣的:(数据结构-线段树(树状数组),折半法)