版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目大意:
给定一个序列,有两种操作
Q:查询这个序列的正序数对数
R:给定区间内的数字向前移动一位
思路:
树状数组可以nlogn求逆序数,那么同样可以求正序数,也是nlogn
当每次移动的时候,就是O(n)的复杂度,但是有m次操作,也就是O(n*m)的复杂度,达到1e7,很容易超时
但是n的范围比较小,所以树状数组里面可以优化一下(见代码)
最后就是记得初始化,和一些细节的处理,注意数据范围
#include <bits/stdc++.h>
using namespace std;
const int maxn=3000000+50;
typedef long long ll;
int n,m,r,l;
ll ans;
char s[10];
int a[maxn],tree[maxn];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int k)
{
while(x<10000)//这里优化
{
tree[x]+=k;
x+=lowbit(x);
}
}
ll getsum(int x)
{
ll res=0;
while(x>0)
{
res+=tree[x];
x-=lowbit(x);
}
return res;
}
int main()
{
while(scanf("%d",&n)==1)
{
memset(tree,0,sizeof tree);
ans=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
update(a[i],1);
ans+=getsum(a[i]-1);
}
scanf("%d",&m);
while(m--)
{
scanf("%s",s);
if(s[0]=='Q')
{
printf("%lld\n",ans);
}
else
{
scanf("%d%d",&l,&r);
int t=a[l];
for(int i=l+1;i<=r;i++)
{
if(a[i]>t)
ans--;
else if(a[i]<t)
ans++;
a[i-1]=a[i];
}
a[r]=t;
}
}
}
return 0;
}