bzoj3289 Mato的文件管理 莫队+树状数组

题目链接:传送门

题目大意:
给定一个 n n n个数的序列,有 q q q个询问,每个询问给出区间 [ l , r ] [l,r] [l,r],要求输出 [ l , r ] [l,r] [l,r]区间内逆序对的数量。
n , q &lt; = 5 ∗ 1 0 4 n,q&lt;=5*10^4 n,q<=5104

容易看出,最小的交换次数=区间逆序对个数(很显然,因为一次交换只能减少一个逆序对)
然后看到这个数据范围,又是序列上的区间问题,所以想到用莫队。
发现这里莫队无法 O ( 1 ) O(1) O(1) [ l , r ] [l,r] [l,r]推出 [ l − 1 , r ] [l-1,r] [l1,r] [ l , r + 1 ] [l,r+1] [l,r+1]的答案。
考虑静态求数组逆序对的方法:加入时,用树状数组询问比当前权值 a [ i ] a[i] a[i]大的个数。
所以这里珂以用树状数组 O ( l o g n ) O(logn) O(logn)维护答案qwq。
总时间复杂度: O ( n n l o g n ) . O(n\sqrt n logn). O(nn logn).

代码

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#define re register int
#define rl register ll
using namespace std;
typedef long long ll;
ll read() {
	rl x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
namespace I_Love {

const int Size=50005;
const int LOG=20;
int n,q,maxn,siz,a[Size],b[Size],belong[Size];
struct Day {
	int id,l,r;
} Q[Size];
inline bool comp(Day x,Day y) {
	if(belong[x.l]!=belong[y.l])	return belong[x.l]<belong[y.l];
	return x.r<y.r;
}
//树状数组维护,记得开long long
ll ans,tree[Size],out[Size];
inline int lowbit(int x) {
	return x&(-x);
}
void update(int x,int val) {
	for(re i=x; i<=n; i+=lowbit(i)) {
		tree[i]+=val;
	}
}
ll query(int x) {
	int ans=0;
	for(re i=x; i; i-=lowbit(i)) {
		ans+=tree[i];
	}
	return ans;
}
inline void addl(int x) {
	ans+=query(x-1);
	update(x,1);
}
inline void addr(int x) {
	ans+=query(maxn)-query(x-1);
	update(x,1);
}
inline void dell(int x) {
	ans-=query(x-1);
	update(x,-1);
}
inline void delr(int x) {
	update(x,-1);
	ans-=query(maxn)-query(x-1);
}
void Fujibayashi_Ryou() {
	n=read();
	siz=sqrt(n);
	for(re i=1; i<=n; i++) {
		b[i]=a[i]=read();
		belong[i]=(i-1)/siz+1;
	}
	sort(b+1,b+1+n);
	maxn=unique(b+1,b+1+n)-(b+1);
	for(re i=1; i<=n; i++) {
		a[i]=lower_bound(b+1,b+1+maxn,a[i])-b;
	}
	q=read();
	for(re i=1; i<=q; i++) {
		Q[i].l=read();
		Q[i].r=read();
		Q[i].id=i;
	}
	sort(Q+1,Q+1+q,comp);
	int l=1,r=0;
	for(re i=1; i<=q; i++) {
		while(r<Q[i].r)	addr(a[++r]);
		while(r>Q[i].r)	delr(a[r--]);
		while(l<Q[i].l)	dell(a[l++]);
		while(l>Q[i].l)	addl(a[--l]);
		out[Q[i].id]=ans;
	}
	for(re i=1; i<=q; i++) {
		printf("%lld\n",out[i]);
	}
}

}
int main() {
	I_Love::Fujibayashi_Ryou();
	return 0;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值