bzoj3289 Mato的文件管理(树状数组求逆序对+莫队+离散化)

来源:互联网 发布:tonymoly口红比mac 编辑:程序博客网 时间:2024/06/12 04:40

首先明确,求交换次数最小其实就是求逆序对的个数。可以用树状数组方便地进行求解。然后题目没说文件大小的范围,我们就赶紧怕怕的采取了离散化。我们还发现这题可以O(logn)的由[l,r]=>[l-1,r]等等。。所以,莫队,就是你啦!具体细节见代码。

#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <map>using namespace std;#define ll long long#define N 50005inline ll read(){ll x=0;char ch=getchar();while(ch<'0'||ch>'9') ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x;}int n,m,block,a[N],c[N];ll b[N],aa[N],ans=0,ANS[N];map<ll,int>Map;struct node{int l,r,id,block;}q[N];inline bool cmp(node x,node y){return x.block==y.block?x.r<y.r:x.block<y.block;}inline int lowbit(int x){return x&(-x);}inline void update(int x,int val){for(;x<=n;x+=lowbit(x)) c[x]+=val;}inline int query(int x){int res=0;for(;x>0;x-=lowbit(x)) res+=c[x];return res; }inline void ask1(int x,int op){update(x,op);//更改左边界,影响值为比x小的个数 ans+=(op*query(x-1));//[1,x-1]前缀和 }inline void ask2(int x,int op){update(x,op);//更改右边界,影响值为比x大的个数 ans+=(op*(query(n)-query(x)));//其实是求[x+1,n]的前缀和 }int main(){//freopen("a.in","r",stdin);n=read();block=sqrt(n);for(int i=1;i<=n;++i) b[i]=read(),aa[i]=b[i];m=read();for(int i=1;i<=m;++i){q[i].l=read();q[i].r=read();q[i].id=i;q[i].block=(q[i].l-1)/block;} sort(q+1,q+m+1,cmp);sort(aa+1,aa+n+1);for(int i=1;i<=n;++i) Map[aa[i]]=i;for(int i=1;i<=n;++i) a[i]=Map[b[i]];int l=1,r=0;for(int i=1;i<=m;++i){for(;l<q[i].l;++l) ask1(a[l],-1);for(;l>q[i].l;--l) ask1(a[l-1],1);for(;r<q[i].r;++r) ask2(a[r+1],1);for(;r>q[i].r;--r) ask2(a[r],-1);ANS[q[i].id]=ans;}for(int i=1;i<=m;++i) printf("%lld\n",ANS[i]);return 0;}