#树状数组#洛谷 5463 小鱼比可爱(加强版)

题目

给定一个长度为\(n\)的序列,求所有区间的逆序对总和


分析

考虑有序数对\((i,j)\)若为逆序对可以给\(i*(n-j+1)\)个区间做贡献
那只要在插入的时候放入\(n-j+1\),查询的时候结果乘\(i\),此题就可以转换为树状数组的经典问题
不过注意要开__int128,如果不想写高精度的话


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
typedef long long lll;
typedef __int128 llll;
const int N=1000011; llll ans;
int n,a[N],b[N],m; lll c[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(llll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline lll query(int x){
	rr lll ans=0;
	for (;x;x-=-x&x) ans+=c[x];
	return ans;
}
inline void update(int x,int y){
	for (;x<=m;x+=-x&x) c[x]+=y;
}
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i) b[i]=a[i]=iut();
	sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1;
	for (rr int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+m,a[i])-b;
	for (rr int i=n;i;--i) ans+=query(a[i]-1)*i,update(a[i],n-i+1);
	print(ans);
	return 0;
} 
posted @ 2020-10-15 17:41  lemondinosaur  阅读(78)  评论(0编辑  收藏  举报