By zhongzijun \text{zhongzijun} zhongzijun
Description
这是 小鱼比可爱 的 加强版 。
给你一个正整数 n n n 和一个序列 a 1 a_1 a1 ~ a n a_n an 。
定义 f ( i , j ) f(i,j) f(i,j) 表示序列 a a a 在 [ l , r ] [l,r] [l,r] 内的逆序对对数。 现在请你求出:
∑ i = 1 n ∑ j = i + 1 n f ( i , j ) \sum_{i=1}^n\sum_{j=i+1}^{n}f(i,j) ∑i=1n∑j=i+1nf(i,j)
。
其中 1 ≤ n ≤ 1 0 6 , 1 ≤ a i ≤ 1 0 9 1 \leq n \leq 10^6,1 \leq a_i \leq 10^9 1≤n≤106,1≤ai≤109 。
时间限制 2 s 2s 2s , 空间限制 256 M B 256MB 256MB 。
Solution
考虑使用 离散化 和 权值线段树 来解题。
考虑一对逆序对 l l l 和 r r r ,它所产生的贡献是 l × ( n − r + 1 ) l\times(n-r+1) l×(n−r+1) 。
显然所有 l l l 的和可以用 权值线段树 来维护。
考虑到 1 ≤ a i ≤ 1 0 9 1 \leq a_i \leq 10^9 1≤ai≤109 ,所以要先把序列 a a a 离散化 一下。
考虑到答案会很大,所以存答案的那个变量要开 __int128
,其他的变量要开 long long
。
记得要注意 __int128
的输出。
时间复杂度 O ( n    log    n ) O(n\;\log\;n) O(nlogn) 。
然后这道题目就做完了,具体的细节见 代码 部分。
Code
#include <cstdio>
#include <cctype>
struct node{ long long l,r,lc,rc,c; } tree[2100001];
long long a[1000001],b[1000001],d[1000001];
long long lenb=0,lend=0,len=0;
inline long long read()
{
long long X=0,w=0;
char ch=0;
while(!isdigit(ch))
{
w|=ch=='-';
ch=getchar();
}
while(isdigit(ch))
X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline void print(__int128 x)
{
if(x<0){putchar('-');x=-x;} if(x>9) print(x/10); putchar(x%10+'0'); } void bt(long long l,long long r) { len++; tree[len].l=l; tree[len].r=r; tree[len].lc=0; tree[len].rc=0; tree[len].c=0; long long now=len; if(l<r) { long long mid=(l+r)/2; tree[len].lc=len+1; bt(l,mid); tree[now].rc=len+1; bt(mid+1,r); } } void change(long long now,long long x,long long t) { if(tree[now].l==tree[now].r) { tree[now].c+=t; return ; } long long mid=(tree[now].l+tree[now].r)/2; if(x<=mid) { change(tree[now].lc,x,t); } else { change(tree[now].rc,x,t); } tree[now].c=tree[tree[now].lc].c+tree[tree[now].rc].c; } long long findsum(long long now,long long l,long long r) { if(tree[now].l==l && tree[now].r==r) { return tree[now].c; } long long mid=(tree[now].l+tree[now].r)/2; if(r<=mid) { return findsum(tree[now].lc,l,r); } else if(mid+1<=l) { return findsum(tree[now].rc,l,r); } else { return findsum(tree[now].lc,l,mid)+findsum(tree[now].rc,mid+1,r); } } void px(long long l,long long r) { long long x=l,y=r,mid=b[(l+r)/2]; while(x<=y) { while(b[x]<mid) { x++; } while(b[y]>mid) { y--; } if(x<=y) { long long t=b[x]; b[x]=b[y]; b[y]=t; x++; y--; } } if(l<y) { px(l,y); } if(x<r) { px(x,r); } } long long find(long long x) { long long l=1,r=lend; while(l<r) { long long mid=(l+r)/2; if(d[mid]<x) { l=mid+1; } else { r=mid; } } return l; } int main() { __int128 ans=0; long long ma=0,n=0; n=read(); for(long long i=1;i<=n;i++) { a[i]=read(); a[i]++; b[++lenb]=a[i]; } px(1,lenb); for(long long i=1;i<=lenb;i++) { if(b[i]!=b[i-1]) { d[++lend]=b[i]; } } for(long long i=1;i<=n;i++) { a[i]=find(a[i]); if(a[i]>ma) { ma=a[i]; } } bt(1,ma+1); change(1,a[1],1); for(long long i=2;i<=n;i++) { ans+=(__int128)findsum(1,a[i]+1,ma+1)*(n-i+1); change(1,a[i],i); } print(ans); return 0; }