【序列莫队+树状数组】BZOJ3289-Mato的文件管理

【题目大意】

一共有n份,每份有一个大小和一个编号。Mato每天随机选一个区间[l,r],拷贝出来(即对原序列不影响),给它们排序,并且每次只能交换相邻两份文件。问每天最少交换几次?

【思路】

显然,每天最少交换次数=[l,r]逆序对的个数。离散化后,用莫队离线查询,用树状数组来维护当前的区间。

假设我们已经知道[l,r]的逆序对的个数,怎样才能求出[l-1,r],[l+1,r],[l,r-1]和l[r+1]呢?

随便考虑序列3,5,2,4,7,6,8,已知[2,4]逆序对的个数为2对。[l-1,r]逆序对的个数有3对,即加上比3小的个数;[l+1,r]逆序对的个数有0对,即减去比5小的个数;[l,r-1]有1对,即减去比4大的数的个数;[l,r+1]有2对,即加上比7大的数的个数,由此可以得出结论:

@AutSky_JadeK

①在一列数的后面添加一个数,逆序对数会增加 数列中比它大的数的个数。

②在一列数的后面删除一个数,逆序对数会减少 数列中比它大的数的个数。

③在一列数的前面添加一个数,逆序对数会增加 数列中比它小的数的个数。

④在一列数的前面删除一个数,逆序对数会减少 数列中比它小的数的个数。

时间复杂度为O(n^1.5*log(n))

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 using namespace std;
  7 struct node
  8 {
  9     int num,pos;
 10     bool operator < (const node &x) const {return num<x.num;}
 11 };
 12 struct queries
 13 {
 14     int l,r,pos,id,ans;
 15 };
 16 const int MAXN=50000+50;
 17 int n,m,size[MAXN],e[MAXN];
 18 node tmpsize[MAXN];
 19 queries q[MAXN];
 20 bool cmp(queries a,queries b)
 21 {
 22     return (a.pos==b.pos)?a.r<b.r:a.pos<b.pos;
 23 }
 24  
 25 bool cmpid(queries a,queries b)
 26 {
 27     return a.id<b.id;
 28 }
 29  
 30 int lowbit(int x)
 31 {
 32     return (x&(-x));
 33 }
 34  
 35 int sum(int p)
 36 {
 37     int ret=0;
 38     while (p>0)
 39     {
 40         ret+=e[p];
 41         p-=lowbit(p);
 42     } 
 43     return ret;
 44 }
 45  
 46 void modify(int p,int x)
 47 {
 48     while (p<=n)
 49     {
 50         e[p]+=x;
 51         p+=lowbit(p);
 52     }
 53 }
 54  
 55 void init()
 56 {
 57     scanf("%d",&n);
 58     for (int i=1;i<=n;i++)
 59     {
 60         scanf("%d",&tmpsize[i].num);
 61         tmpsize[i].pos=i;
 62     }
 63     sort(tmpsize+1,tmpsize+n+1);
 64     for (int i=1,j=0;i<=n;i++) 
 65     {
 66         if (i==1 || tmpsize[i].num!=tmpsize[i-1].num) j++;
 67         size[tmpsize[i].pos]=j;
 68     }
 69     scanf("%d",&m);
 70     int block=int(sqrt(n));
 71     for (int i=1;i<=m;i++)
 72     {
 73         scanf("%d%d",&q[i].l,&q[i].r);
 74         q[i].id=i;
 75         q[i].pos=(q[i].l-1)/block+1;
 76     }
 77     sort(q+1,q+m+1,cmp);
 78 }
 79  
 80 void query()
 81 {
 82     memset(e,0,sizeof(e));
 83     int l=1,r=0,ans=0;
 84     for (int i=1;i<=m;i++)
 85     {
 86         while (l<q[i].l) modify(size[l],-1),ans-=sum(size[l]-1),l++;
 87         while (l>q[i].l) l--,modify(size[l],1),ans+=sum(size[l]-1);
 88         while (r>q[i].r) modify(size[r],-1),ans-=r-l-sum(size[r]),r--;
 89         while (r<q[i].r) r++,modify(size[r],1),ans+=r-l+1-sum(size[r]);
 90         q[i].ans=ans;
 91     }
 92     sort(q+1,q+m+1,cmpid);
 93     for (int i=1;i<=m;i++) printf("%d\n",q[i].ans);
 94 }
 95  
 96 int main()
 97 {
 98     init();
 99     query();
100     return 0;
101 }

 

posted @ 2016-07-26 21:07  iiyiyi  阅读(178)  评论(0编辑  收藏  举报