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.
1≤T≤5,1≤N≤50000
Output
For each testcase,print the ans.
Sample Input
1
3
0 1 2
Sample Output
3 1 2
解:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n,t;
const int N=50010;
int a[N];
int sum[N<<2];
int output[N];
int ls(int p) {return p<<1;}
int rs(int p) {return p<<1|1;}
void pushup(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int p,int l,int r){
if(l==r){
sum[p]=1;
return ;
}
int mid=(r+l)>>1;
build(ls(p),l,mid);
build(rs(p),mid+1,r);
pushup(p);
}
int query(int p,int l,int r,int k){
if(l==r){
sum[p]=0;
return l;
}
int res;
int mid=(r+l)>>1;
if(sum[rs(p)]>=k)
res=query(rs(p), mid+1,r,k);
else
res=query(ls(p),l,mid,k-sum[rs(p)]);//
pushup(p);
return res;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
build(1,1,n);
a[0]=0;
for(int i=n; i>=1; i--){
int cnt=a[i]-a[i-1];
output[i]=query(1,1,n,cnt+1);
}
for(int i=1; i<n;++i) printf("%d ",output[i]);
printf("%d\n",output[n]);
}
}
再贴一个树状数组求第K大的,这还要用到二分了,因为树状数组只能维护前缀和。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 50005;
int f[maxn];
int c[maxn];
int ans[maxn];
int lowbit(int x)
{
return x & (-x);
}
void add(int pos, int num, int n)
{
while (pos <= n)
{
c[pos] += num;
pos += lowbit(pos);
}
}
int getSum(int pos)
{
int sum = 0;
while (pos > 0)
{
sum += c[pos];
pos -= lowbit(pos);
}
return sum;
}
void init(int n)
{
memset(c, 0, sizeof(c));
for (int i = 1; i <= n; i++)
add(i, 1, n);
}
int search(int k, int n)
{
int l = 1, r = n, mid;
while (l <= r)
{
mid = (l + r) / 2;
int sum = getSum(mid);
if (sum >= k) r = mid - 1;
else l = mid + 1;
}
return l;
}
int main()
{
int T, n;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
init(n);
for (int i = 1; i <= n; i++)
scanf("%d", &f[i]);
for (int i = n; i >= 1; i--)
{
int k = f[i] - f[i - 1];//第k+1大
k = i - k;//在剩下的里面第i - k 小
int pos = search(k, n);//二分找出第k小的位置
ans[i] = pos;
add(pos, -1, n);
}
for (int i = 1; i < n; i++) printf("%d ", ans[i]);
printf("%d\n", ans[n]);
}
return 0;
}
还有一个神仙模拟 600多毫秒,线段树140毫秒 但是人家短啊!
#include<bits/stdc++.h>
using namespace std;
const int N=50005;
int ans[N];
vector<int>vec;
int main(){
int t,n,x;
scanf("%d",&t);
while(t--){
vec.clear();
scanf("%d",&n);
int pre=0,tem;
for(int i=1;i<=n;++i){
scanf("%d",&x);
tem=x-pre;
pre=x;
// cout<<"tem="<<tem<<" "<<i<<endl;
vec.insert(vec.begin()+tem,i);
// for(int j=0;j<vec.size();++j) printf("%d ",vec[j]);puts("");
}
for(int i=0;i<n;++i)ans[vec[i]]=n-i;
for(int i=1;i<n;++i)printf("%d ",ans[i]);
printf("%d\n",ans[n]);
//for(int i=0;)
}
}
而且我还不是很理解= =