[bzoj3289]Mato的文件管理_莫队_树状数组

Mato的文件管理 bzoj-3289

题目大意:给定一个n个数的序列。m次询问:一段区间中的逆序对个数。

注释:$1\le n\,mle 5\cdot 10^4$。


想法

开始想这个题的大佬们,给您点儿提示吧:$O(nlogn\sqrt(n))$可过哦!

所以这个题就是莫队的裸题了。

我们的莫队上的区间在动的时候随时更新树状数组上的信息即可。、

然后碰见了一整块区间,我们就直接求逆序对即可,

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 50010 
using namespace std;
struct Query {int l,r,id;}q[N]; int L[N],R[N],maxval,tree1[N<<1],tree2[N<<1],blg[N],a[N],ans[N];
inline bool cmp_dispose(const Query &x,const Query &y) {return blg[x.l]==blg[y.l]?x.r<y.r:blg[x.l]<blg[y.l];}
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
inline int lowbit(int x) {return x&(-x);}
void update1(int x,int val) {for(int i=x;i>=1;i-=lowbit(i)) tree1[i]+=val;}
void update2(int x,int val) {for(int i=x;i<=maxval;i+=lowbit(i)) tree2[i]+=val;}
inline void update(int x,int val) {update1(x,val); update2(x,val);}
int query1(int x) {int ans=0; for(int i=x;i<=maxval;i+=lowbit(i)) ans+=tree1[i]; return ans;}
int query2(int x) {int ans=0; for(int i=x;i>=1;i-=lowbit(i)) ans+=tree2[i]; return ans;}
int main()
{
	int n=rd(); int t=sqrt(n); int blck=n/t;
	for(int i=1;i<=blck;i++)
	{
		int bfr=(i-1)*t;
		L[i]=bfr+1; R[i]=bfr+t;
		for(int j=1;j<=t;j++)
		{
			blg[bfr+j]=i;
			a[bfr+j]=rd();
			maxval=max(maxval,a[bfr+j]);
		}
	}
	if(blck*t<n)
	{
		L[blck+1]=blck*t; R[blck+1]=n; blck++;
		for(int j=blck*t+1;j<=n;j++)
		{
			blg[j]=blck; a[j]=rd(); maxval=max(maxval,a[j]);
		}
	}
	int m=rd();
	for(int i=1;i<=m;i++) q[i].l=rd(),q[i].r=rd(),q[i].id=i;
	sort(q+1,q+m+1,cmp_dispose);
	int point_l=q[1].l,point_r=q[1].r; for(int i=point_l;i<=point_r;i++)
	{
		ans[q[1].id]+=query1(a[i]+1); update(a[i],1);
	}
	for(int i=2;i<=m;i++)
	{
		int idx=q[i].id;
		while(point_l<q[i].l)
		{
			update(a[point_l],-1);
			ans[idx]-=query2(a[point_l]-1);
			point_l++;
		}
		while(point_l>q[i].l)
		{
			point_l--;
			update(a[point_l],1);
			ans[idx]+=query2(a[point_l]-1);
		}
		while(point_r<q[i].r)
		{
			point_r++;
			update(a[point_r],1);
			ans[idx]+=query1(a[point_r]+1);
		}
		while(point_r>q[i].r)
		{
			update(a[point_r],-1);
			ans[idx]-=query1(a[point_r]+1);
			point_r--;
		}
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
	return 0;
}

小结:莫队真的强..

转载于:https://www.cnblogs.com/ShuraK/p/9662125.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值