通过分析可得一个点它最右边的位置就是他现在的位置加上他后面的比他小的数字的个数。
一个点最左边的位置就是他开始的位置或者排完序以后的位置min(i,num[i]);
用数组数组从后往前可以巧妙的维护一个点后面符合条件的点有多少个,具体看代码。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100005;
int n;
int num[maxn];
int tree[maxn];
int ans[maxn];
int lowbit(int i)
{
return i&(-i);
}
void add(int i,int x)
{
while(i<=n)
{
tree[i] += x;
i += lowbit(i);
}
}
int query(int i)
{
int sum = 0;
while(i)
{
sum += tree[i];
i -= lowbit(i);
}
return sum;
}
int main()
{
int cases,t = 1;
scanf("%d",&cases);
while(cases--)
{
memset(tree,0,sizeof(tree));
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
for(int i=n;i>=1;i--)
{
int res = query(num[i]);
add(num[i],1);
ans[num[i]] = res+i-min(num[i],i);
}
printf("Case #%d:",t++);
for(int i=1;i<=n;i++) printf(" %d",ans[i]); printf("\n");
}
return 0;
}