[bzoj3289]Mato的文件管理

来自FallDream的博客,未经允许,请勿转载,谢谢。


 

Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号。为了防止他人偷拷,这些资料都是加密过的,只能用Mato自己写的程序才能访问。Mato每天随机选一个区间[l,r],他今天就看编号在此区间内的这些资料。Mato有一个习惯,他总是从文件大小从小到大看资料。他先把要看的文件按编号顺序依次拷贝出来,再用他写的排序程序给文件大小排序。排序程序可以在1单位时间内交换2个相邻的文件(因为加密需要,不能随机访问)。Mato想要使文件交换次数最小,你能告诉他每天需要交换多少次吗?  n<=50000

 

求的是区间的逆序对数量... 所以直接莫队+线段树转移就行了。复杂度$O(n^{\frac{3}{2}}logn)$

当然还可以分块,选择根号个点,处理出每个点到所有点的答案,然后每次询问暴力跳 上个主席树查逆序对数量就行了  复杂度一样 但是支持在线

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define MN 50000
#define N 65534
#define ll long long
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

int n,s[MN+5],m,cnt=1,size,block[MN+5],T[N*2+5],L,R,l[MN+5];
struct ques{int l,r,id;}q[MN+5];
bool cmp(ques x,ques y){return block[x.l]==block[y.l]?x.r<y.r:x.l<y.l;}
ll ans=0,Ans[MN+5];

inline int query(int l,int r)
{
    if(l>r) return 0;int sum=0;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) sum+=T[l+1];
        if( r&1) sum+=T[r-1];    
    }
    return sum;
}

void renew(int x,int ad)
{
    T[x+=N]+=ad;
    for(x>>=1;x;x>>=1) T[x]=T[x<<1]+T[x<<1|1];    
}

inline void insL(int x,int ad)
{
    ans+=ad*query(1,s[x]-1);    
    renew(s[x],ad);
}

inline void insR(int x,int ad)
{
    ans+=ad*query(s[x]+1,cnt);
    renew(s[x],ad);    
}

int main()
{
    n=read();size=sqrt(n);
    for(int i=1;i<=n;++i) block[i]=(i-1)/size+1;
    for(int i=1;i<=n;++i) s[i]=l[i]=read();    
    sort(l+1,l+n+1);
    for(int i=2;i<=n;++i) if(s[i]!=s[i-1]) s[++cnt]=s[i]; 
    for(int i=1;i<=n;++i) s[i]=lower_bound(l+1,l+cnt+1,s[i])-l;
    m=read();
    for(int i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
    sort(q+1,q+m+1,cmp);
    for(int i=1,last=0;i<=m;++i)
    {
        if(block[q[i].l]!=last) 
        {
            memset(T,0,sizeof(T));
            insL(L=R=(block[q[i].l]-1)*size+1,1);    
            last=block[q[i].l];ans=0;
        }
        while(L<q[i].l) insL(L++,-1);
        while(L>q[i].l) insL(--L, 1);
        while(R<q[i].r) insR(++R, 1);
        Ans[q[i].id]=ans;
    }
    for(int i=1;i<=m;++i) printf("%lld\n",Ans[i]);
    return 0;
}
posted @ 2017-05-02 09:35  FallDream  阅读(259)  评论(0编辑  收藏  举报