• 【序列莫队+树状数组】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
    ",q[i].ans);
     94 }
     95  
     96 int main()
     97 {
     98     init();
     99     query();
    100     return 0;
    101 }
  • 相关阅读:
    codeforces484A
    codeforces559B
    spfa算法及判负环详解
    清北学堂提高组突破营考试T1
    lemon用法
    清北学堂提高组突破营游记day6
    清北学堂提高组突破营游记day5
    POJ-1679 The Unique MST (判断最小生成树的唯一性)
    HDU 4553 约会安排 (区间合并)【线段树】
    POJ 1236 Network Of Schools (思维+强连通)
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5708949.html
Copyright © 2020-2023  润新知