Mar 13th T1 树状数组逆序对的简单性质应用(

Problem 1. rotinv

如果你有一个长度为\(n\)的序列:

\[a_1,a_2,a_3,...a_n \]

那么它的一个逆序对是一二元组\(<i,j>\)满足\(i<j\)\(a_i>a_j\),其中\(i,j\in[1,n]\)
我们称一个序列所包含的逆序对数为这个序列的逆序对数。
那么问题来了:
给出一个长度为n的序列,需要计算

\[a_1,a_2...a_{n-1},a_n \]

\[a_2,a_3...a_n,a_1 \]

\[a_3,a_4...a_1,a_2 \]

\[... \]

\[a_n,a_1...a_{n-2},a_{n-1} \]

\(n\)个序列的逆序对之和。

\(n≤10^6,1≤a_i≤n\)

Sol

考虑求初始序列\(a_1..a_n\),就是树状数组逆序对板子。
现在考虑把\(a_i\)丢到最后面的影响。
我们令\(f[a[i]]\)为序列\(n\)\(i,j\)非逆序对的个数(即\(a_i>=a_j\)\(i>j\))(你的树状数组的\(query\)写的应该就是这东西)
则新增加的逆序对个数显然为\(n-f[a[i]]\)

注意到除了新增加的,也有减少的。
即所有\(j\)使得\(j>1\)(当时\(i\)的位置)且\(a_j<a_i\)所构成的逆序对都不存在了,因为\(i\)被丢到了最后。
换句话说就是所有比\(i\)小的。
如何求减少的?因为\(f[a[i]-1]\).
就这。还在考试写的有点糊,不保证除了自己以外的人能看得懂(((

#include <iostream>
#include <cstdio>
#include <cstring>
#define lb(x) (x&(-x))
#define re register int
#define maxn 1000005
#define ll long long
using namespace std;
inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}
int a[maxn];
int tr[maxn];
int n; 
inline void add(int x){
	for(re i=x;i<=n;i+=lb(i)){
		tr[i]++;
	}
}
inline int query(int x){
	int ans=0;
	for(re i=x;i;i-=lb(i)){
		ans+=tr[i];
	}
	return ans;
}
void file(){
	freopen("rotinv.in","r",stdin);
	freopen("rotinv.out","w",stdout);
}
int main(void){
	//file();
	n=read();
	ll L=0;
	for(re i=1;i<=n;i++){
		a[i]=read();
		add(a[i]);
		L+=i-query(a[i]);
	}
	ll ans=0;
	for(re i=1;i<=n;i++){
		L+=n-query(a[i])-query(a[i]-1);
		ans+=L;
	}
	printf("%lld\n",ans);
	return 0;
}

\(P\):关于为啥要写这玩意:懒得写\(T3\)

posted @ 2021-03-13 11:16  xxbzzyw  阅读(64)  评论(1编辑  收藏  举报