杀鸡用牛刀!!!
  • 板块学术版
  • 楼主Y_Naidong
  • 当前回复7
  • 已保存回复7
  • 发布时间2024/7/13 10:09
  • 上次更新2024/7/13 10:26:27
查看原帖
杀鸡用牛刀!!!
997515
Y_Naidong楼主2024/7/13 10:09

逆序对

题目描述

猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。

最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai>aja_i>a_j 且 i<ji<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。

Update:数据已加强。

输入格式

第一行,一个数 nn,表示序列中有 nn个数。

第二行 nn 个数,表示给定的序列。序列中每个数字不超过 10910^9。

输出格式

输出序列中逆序对的数目。

样例 #1

样例输入 #1

6
5 4 2 6 3 1

样例输出 #1

11

提示

对于 25%25\% 的数据,n≤2500n \leq 2500

对于 50%50\% 的数据,n≤4×104n \leq 4 \times 10^4。

对于所有数据,n≤5×105n \leq 5 \times 10^5

请使用较快的输入输出

应该不会 O(n2)O(n^2) 过 50 万吧 by chen_zhe :)


#include<bits/stdc++.h>
using namespace std;
int n,m;
long long tree[10000001],tag[10000001],a[10000001];
int ls(int x){return x*2;}
int rs(int x){return x*2+1;}
void up(int ix){tree[ix]=tree[ls(ix)]+tree[rs(ix)];}

struct node{int x,ix,l;}p[10000001];
int cmp1(node p1,node p2){return p1.x<p2.x;}
int cmp2(node p1,node p2){return p1.ix<p2.ix;}


void downp(int l,int r,int ix){
	if(tag[ix]){
		tag[ls(ix)]+=tag[ix];
		tag[rs(ix)]+=tag[ix];
		int mid=(l+r)/2;
		tree[ls(ix)]+=tag[ix]*(mid-l+1);
		tree[rs(ix)]+=tag[ix]*(r-mid);
		tag[ix]=0;
	}
	return;
}
void build(int l,int r,int ix){
	if(l==r){
		tree[ix]=a[l];
		return;
	}
	int mid=(l+r)/2;
	build(l,mid,ls(ix));
	build(mid+1,r,rs(ix));
	up(ix);
}
void change(int l,int r,int x,int y,int ix,int k){
	if(x<=l&&r<=y){
		tree[ix]+=k*(r-l+1);
		tag[ix]+=k;
		return;
	}
	downp(l,r,ix);
	int mid=(l+r)/2;
	if(x<=mid)
		change(l,mid,x,y,ls(ix),k);
	if(y>mid)
		change(mid+1,r,x,y,rs(ix),k);
	up(ix);
}
long long query(int l,int r,int x,int y,int ix){
	if(x<=l&&r<=y){
		return tree[ix];
	}
	downp(l,r,ix);
	int mid=(l+r)/2;
	long long ans=0;
	if(x<=mid)
		ans+=query(l,mid,x,y,ls(ix));
	if(mid<y)
		ans+=query(mid+1,r,x,y,rs(ix));
	return ans;
}
int main(){
	cin>>n;
	build(1,n,1);
	for(int i=1;i<=n;i++){
		scanf("%d",&p[i].x);
		p[i].ix=i;
	}
	sort(p+1,p+1+n,cmp1);
	int o=1;
	for(int i=1;i<=n;i++){
		if(p[i].x==p[i-1].x){
			p[i].l=o;
			continue;
		}
		o=i;
		p[i].l=o;
	}
	sort(p+1,p+n+1,cmp2);
	long long ans=0;
	for(int i=1;i<=n;i++){
		a[i]=p[i].l;
		change(1,n,a[i],a[i],1,1);
		if(a[i]+1<=n){
			ans+=query(1,n,a[i]+1,n,1);
		}
	}
	cout<<ans;
	return 0;
}

线段树

2024/7/13 10:09
加载中...