bzoj3289Mato的文件管理

bzoj3289Mato的文件管理

题意:

一共有n份资料,每天随机选一个区间[l,r],Mato按文件从小到大的顺序看编号在此区间内的这些资料。他先把要看的文件按编号顺序依次拷贝出来,再用排序程序给文件大小排序。求每天排序时的交换次数。

题解:

还是莫队,但是转移的时候用树状数组维护逆序对个数,总复杂度为O(nsqrt(n)log2n)。因为是从大到小插入的,所以维护时要用r-l+1减。

代码:

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <cmath>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define lowbit(a) a&(-a)
 7 #define ll long long
 8 using namespace std;
 9 
10 struct nd1{int x,y;};
11 bool cmp1(nd1 a,nd1 b){return a.x<b.x;}
12 struct nd2{int l,pl,r; ll ans; int id;};
13 bool cmp2(nd2 a,nd2 b){if(a.pl!=b.pl)return a.pl<b.pl; if(a.r!=b.r)return a.r<b.r; return a.l<b.l;}
14 bool cmp3(nd2 a,nd2 b){return a.id<b.id;}
15 ll c[100000],ans,l,r; int n,q,ls[100000],pos[100000]; nd1 f[100000]; nd2 ask[100000];
16 inline void add(int x,ll y){while(x<=n)c[x]+=y,x+=lowbit(x);}
17 inline ll query(int x){ll qy=0; while(x>=1)qy+=c[x],x-=lowbit(x); return qy;}
18 int main(){
19     scanf("%d",&n); inc(i,1,n)scanf("%d",&f[i].x),f[i].y=i; sort(f+1,f+n+1,cmp1);
20     inc(i,1,n)ls[f[i].y]=i; int sz=(int)sqrt(n); inc(i,1,n)pos[i]=(i-1)/sz+1;
21     scanf("%d",&q); inc(i,1,q){int a,b; scanf("%d%d",&a,&b); ask[i]=(nd2){a,pos[a],b,0,i};}
22     sort(ask+1,ask+1+q,cmp2); memset(c,0,sizeof(c)); ans=0; l=1; r=0;
23     inc(i,1,q){
24         while(r<ask[i].r){int x=r+1; x=n-ls[x]; ll a1=query(x); ans+=a1; add(x+1,1); r++;}
25         while(l>ask[i].l){int x=l-1; x=n-ls[x]; ll a1=(r-l+1)-query(x); ans+=a1; add(x+1,1); l--;}
26         while(r>ask[i].r){int x=r; x=n-ls[x]; ll a1=query(x); ans-=a1; add(x+1,-1); r--;}
27         while(l<ask[i].l){int x=l; x=n-ls[x]; ll a1=(r-l)-query(x); ans-=a1; add(x+1,-1); l++;}
28         ask[i].ans=ans;
29     }
30     sort(ask+1,ask+1+q,cmp3); inc(i,1,q)printf("%lld\n",ask[i].ans);
31     return 0;
32 }

 

20160408

posted @ 2016-07-22 19:53  YuanZiming  阅读(138)  评论(0编辑  收藏  举报