CF1167F Scalar Queries (线段树/树状数组)
阅读原文时间:2023年07月10日阅读:1

题意

题解

对于[l,r]中的一个数,不论[l,r]有多大,只有比它小的数可以影响到它的排名,那么就可以把ai从小到大排序,一个一个加入线段树中,线段树中下表为 i 的是ai(原来的位置,不是排序后的)分别为最右端和最左端时的排名总和(设为suml[i]、sumr[i]),ai的总贡献就是 ai * (suml[i-1] * (n-i+1) + sumr[i] * i)

当循环到一个点 i 时,他左边的任意一个点 j 会为 l <= j 且 r >= i 的区间中 i 的排名贡献1,右边的任意一个点 k 会为 l <= i 且 r >= k 的区间中 i 的排名贡献1,他自己也有贡献

所以加入一个点 i 时,就要把 i~n 的 suml 都加上 i ,把 1~i 的 sumr 都加上 n-i+1。

CODE

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#define MAXN 500005
#define MAXM 1000005
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x)&(x))
//#define int LL
//#pragma GCC optimize(2)
using namespace std;
inline LL read() {
    LL f = 1,x = 0;char s = getchar();
    while(s < '0' || s > '9') {if(s == '-')f = -1;s = getchar();}
    while(s >= '0' && s <= '9') {x = x * 10 + (s - '0');s = getchar();}
    return x * f;
}
const int jzm = 1000000007;
int n,m,i,j,s,o,k;
struct it{
    int nm,id;
}a[MAXN];
bool cmp(it a,it b) {return a.nm < b.nm;}
int cl[MAXN],cr[MAXN];
void addt(int *c,int x,int y) {
    while(x <= n) {
        c[x] = (c[x] +0ll+jzm + y) % jzm;
        x += lowbit(x);
    }return ;
}
int sum(int *c,int x) {
    int as = 0;
    while(x > 0) {
        as = (as +0ll+jzm + c[x]) % jzm;
        x -= lowbit(x);
    }
    return as;
}
int main() {
    n = read();
    for(int i = 1;i <= n;i ++) {
        a[i].nm = read();a[i].id = i;
    }
    sort(a + 1,a + 1 + n,cmp);
    int ans = 0;
    for(int i = 1;i <= n;i ++) {
        addt(cl,a[i].id,a[i].id);
        addt(cr,1,n - a[i].id + 1);
        addt(cr,a[i].id+1,a[i].id - n - 1);
        ans = (ans +0ll+jzm +(sum(cl,a[i].id-1) *1ll* (n - a[i].id + 1) % jzm +0ll+ sum(cr,a[i].id) *1ll* a[i].id % jzm) % jzm *1ll* a[i].nm % jzm) % jzm;
//        printf("ans: %d\n",ans);
    }
    printf("%d\n",ans);
    return 0;
}