之前总想数据离散化,结果发现六个0的结果不是0…此路不通!
1.不用数据离散化,离散化了原来相同的就不是加到一个端点上了
2.i前面有i-1个数,可能构成i-1个顺序对和逆序对,所以逆序对=顺序对-逆序对,=i-1-query(i-1) ? 不对!除了逆序对和顺序对,还有可能是相同的,树状数组本身加上了自己这个数,重复的加上去还是会加到这个端点上,所以加上和自己的话构成n的顺序对或逆序对或相等对。应该是i-query(i) 这里i从1开始。i是第i个数,如果相等,加进去端点相等,i也会加1.
反正考虑tree[i]结点本身就会考虑到相等的情况。再多想想吧。
如果要求前i个数比a[i]小的,就是求比它小的数有多少个的话,res=query(a[i]-1)。
如果反过来,前i个数有比a[i]小的也有比a[i]大的,这时候就不能直接求,需要间接减,问题就出在这里。如果没有相同元素,i-1-query(i-1)就好了。但是如果有相同元素,就得i-query(a[i])了。这里面差的不是1,如果相等的元素有很多,i相应加多少,query(a[i])也会相应加多少,因为树状数组节点本身就包含了自己。
不离散化的话,需要把每个人的身高+1,因为题目设置身高可以为0,而代码后面有query(a[i]-1),如果如果不+1会越界 我认为是树状数组的下标是从1开始的,加到0上,不会往树上累加。所以如果不离散化,就应该避免这个情况,每个都+1.。。这咋想啊。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1000001;
typedef long long int ll;
ll tree[N];
ll a[N],re[N];
ll res[N];
int n;
ll m=0;
int lowbit(int x)
{
return x&-x;
}
void add(int x)
{
for(int i=x;i<=m+1;i+=lowbit(i))
tree[i]+=1;
}
ll query(int x)
{
ll re=0;
for(int i=x;i>=1;i-=lowbit(i))
re+=tree[i];
return re;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
m=max(m,++a[i]);
}
for(int i=1;i<=n;i++)
{
add(a[i]);
res[i]=i-query(a[i]);//逆序对数,前面多少个比它大的
}
//for(int i=1;i<=n;i++) cout<<res[i]<<" ";cout<<endl;
memset(tree,0,sizeof(tree));
for(int i=n;i>=1;i--)
{
add(a[i]);
// cout<<query(a[i]-1)<<" ";
res[i]+=query(a[i]-1);
}
//for(int i=1;i<=n;i++) cout<<res[i]<<" ";
ll sum=0;
for(int i=1;i<=n;i++)
{
sum+=(res[i]+1)*res[i]/2;
}
cout<<sum;
}
如果能直接找出来,直接query(a[i]-1),
如果先放进去的是大的再放进去小的,就检测不出来,就得减,一共多少个数再减去能检测出来的,就是要求的,即 i - query(a[i]),i是放进去的总个数,query(a[i])是能检测出来的。
可以离散化,不过还得去重。
离散化:
/*
按从大到小的顺序排的,比按从小到大的顺序排麻烦一点。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 100001;
int tree[N];
int a[N];//鍘婚噸鍚庣殑绂绘暎鍖?
int res[N];
int n;
struct nod{
int data;
int index;
}node[N];
int lowbit(int i)
{
return i&-i;
}
void add(int x)
{
for(int i=x;i<=n;i+=lowbit(i))
tree[i]++;
}
int query(int x)
{
int res=0;
for(int i=x;i>=1;i-=lowbit(i))
res+=tree[i];
// cout<<"1~"<<x<<"的和是"<<res<<endl;
return res;
}
bool cmp(nod a,nod b)
{
return a.data>b.data;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&node[i].data);
node[i].index=i;
}
sort(node+1,node+1+n,cmp);
// for(int i=1;i<=n;i++)
// cout<<node[i].index;cout<<endl;
int index=1;
for(int i=1;i<=n;i++)
{
if(i!=1&&node[i].data!=node[i-1].data)
index++;
a[node[i].index]=index;
}
// for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
for(int i=1;i<=n;i++)
{
add(a[i]);
res[i]+=query(a[i]-1);
}
// for(int i=1;i<=n;i++)
// cout<<res[i]<<" ";cout<<endl;
memset(tree,0,sizeof(tree));
for(int i=n;i>=1;i--)
{
add(a[i]);
res[i]+=n-i+1-query(a[i]);
}
long long int sum=0;
for(int i=1;i<=n;i++)
{
// cout<<res[i]<<" ";
sum+=(long long int)(res[i]+1)*res[i]/2;
}
// cout<<endl;
cout<<sum;
}
/*
按从小到大排,就是按正常顺序,前面找比他大的,后面找比它小的
前面求一次逆序对,后面求顺序对
前面求i-query(i),后面求query(i-1)
按从大到小排,前面找比它小的,后面找比它大的。
前面求逆序对,后面求顺序对
前面是query(i-1),后面是i-query(i);
*/
*/