1017 珂朵莉的数列 离散化 树状数组 逆序区间 贡献计算

链接:https://ac.nowcoder.com/acm/contest/26896/1017
来源:牛客网

题目描述

珂朵莉给了你一个序列,有n×(n+1)2\frac{n\times(n+1)}22n×(n+1)个子区间,求出她们各自的逆序对个数,然后加起来输出

输入描述:

第一行一个数 n 表示这个序列 a 的长度

之后一行 n 个数,第i个数表示ai

输出描述:

输出一行一个数表示答案
示例1

输入

复制
10
1 10 8 5 6 2 3 9 4 7

输出

复制
270
示例2

输入

复制
20
6 0 4 5 8 8 0 6 6 1 0 4 6 6 0 0 7 2 0 5

输出

复制
3481

备注:

对于100%的数据,n <=
1000000 ,0 <= 序列中每个数 <= 1000000000

 分析

由数据范围,肯定不能暴力,只能累计,计算贡献。

对于两个数a[i] 和 a[j] 它们的贡献是在以 [1,i] 为左端点 和以 [j,n] 为右端点的所有区间都有一个贡献,所以计算出前面的所有左端点的累计数量 乘上 (n-j+1)即可

值得注意的是数据范围1e6+10,不是1e5,lower_bound可以给数组用,找到它在数组中的位置,add(a[i],i) 要+i 才是所有左端点的累计数量。

 

 
//-------------------------代码----------------------------

#define int ll
const int N = 1e6+10;
int n,m;
int a[N];
int sum[N];

int tr[N];

int lowbit(int x) {
    return x & -x;
}

void add(int x,int c) {
    for(int i = x;i<=N;i+=lowbit(i)) {tr[i] += c;}
}

ll query(ll x) {
    ll res = 0;for(int i = x;i;i-=lowbit(i)) res += tr[i];return res;
}

void build(int u,int l,int r) {
    
}
int b[N];


void print(__int128_t x) {
    if(x < 0) {putchar('-'),x = -x;}
    if(x > 9) print(x / 10);
    putchar(x % 10 + '0');
}

void solve()
{
//    cin>>n>>m;
    read(n);
    fo(i,1,n) {
        read(a[i]);
        b[i] = a[i];
    }
    sort(b+1,b+1+n);
    
    fo(i,1,n) a[i] = lower_bound(b+1,b+1+n,a[i]) - b + 1;
    __int128_t res = 0;
    fo(i,1,n) {
        res  += (query(N-3) - query(a[i])) * (n-i+1);
        add((a[i]),i);
    }
    print(res);
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-08-10 01:21  er007  阅读(32)  评论(0)    收藏  举报