BZOJ3289 Mato的文件管理 莫队 树状数组
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ3289.html
题目传送门 - BZOJ3289
题意
给定一个序列 $a$ , 有 $n$ 个元素。
给定 $m$ 次询问,每次问一个区间内,只通过交换相邻元素,问至少交换多少次才能使得区间升序。
$n,m\leq 50000$ , $a_i$ 需要离散化
题解
一道不动脑子的题目。
就是询问区间逆序对数。
莫队裸题 + 树状数组。(差点忘了还有树状数组)
wa 了一波。25分钟搞定。30分钟博客也搞定了。
(我一般只有写裸题题解的时候才这么随意……)
代码
#include <bits/stdc++.h> using namespace std; const int N=50005; int n,m,hs=1,a[N],Ha[N]; int c[N]; void HASH(){ sort(Ha+1,Ha+n+1); for (int i=2;i<=n;i++) if (Ha[i]!=Ha[i-1]) Ha[++hs]=Ha[i]; } struct Query{ int L,R,id,ans; }q[N]; bool cmp(Query a,Query b){ int La=a.L>>9,Lb=b.L>>9; if (La!=Lb) return La<Lb; return a.R<b.R; } void add(int x,int d){ for (;x<=hs;x+=x&-x) c[x]+=d; } int sum(int x){ int ans=0; for (;x>0;x-=x&-x) ans+=c[x]; return ans; } bool cmpid(Query a,Query b){ return a.id<b.id; } int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]),Ha[i]=a[i]; HASH(); for (int i=1;i<=n;i++) a[i]=lower_bound(Ha+1,Ha+hs+1,a[i])-Ha; scanf("%d",&m); for (int i=1;i<=m;i++) scanf("%d%d",&q[i].L,&q[i].R),q[i].id=i; sort(q+1,q+m+1,cmp); int L=1,R=0,ans=0; memset(c,0,sizeof c); for (int i=1;i<=m;i++){ while (R<q[i].R) ans+=sum(hs)-sum(a[++R]),add(a[R],1); while (L>q[i].L) ans+=sum(a[--L]-1),add(a[L],1); while (L<q[i].L) add(a[L],-1),ans-=sum(a[L++]-1); while (R>q[i].R) add(a[R],-1),ans-=sum(hs)-sum(a[R--]); q[i].ans=ans; } sort(q+1,q+m+1,cmpid); for (int i=1;i<=m;i++) printf("%d\n",q[i].ans); return 0; }