zoukankan      html  css  js  c++  java
  • bzoj2141排队(辣鸡但是好写的方法)

    题意很明确,也非常经典:

    一个支持查询 区间中比k大的数的个数 并且支持单点修改的序列

    ——因为题意可以转化为:查询这两个数中比后者大的个数、比后者小的个数、比前者大的个数、比前者小的个数(根据这4个就能算出增加/减少了多少对逆序对)并且把两个数修改掉

    于是就出现了

    ——来自百度

    一个二分就能解决套个卵蛋woc身为一个蒟蒻,表示没有一个写得出的

    于是我就想了一个好写(Rank100+几乎T掉)的方法:

    首先复制一份原数据,把一份分块,并且保证每一块中的单调(也就是调用sqrt(n)次排序)

    然后在查询时对于单块暴力处理,对于整块二分查找;修改时冒泡(呵呵,不要吐槽)

    ——一听复杂度就好大,那就算一算吧

    首先要排序O(sqrt(n)*sqrt(n)*lg sqrt(n))              //sqrt(n)次的排序,每次nlgn(这里的n为原题的sqrt(n))

    其次是查询O(m*(sqrt(n)+sqrt(n)*lg sqrt(n)))      //总共有m次,每次零散的有sqrt(n)个,整块的有sqrt(n)块,每块费时lg sqrt(n)

    最后是修改O(m*(sqrt(n)+sqrt(n)))                       //冒个泡应该不用解释,每次收尾都需要冒一遍,一遍最多sqrt(n)次移动

    然后愉快地堆起来变成预处理O(n*lg sqrt(n))主体O(m*sqrt(n)*lgn)

    介于数据弱(如果按套来套去的结构算好像还可以加大一点数据,但是蒟蒻表示受不了,这么个简单思路我调了一下午),我还是过掉了

    代码风格属于臭婆娘的擦脚布,不喜勿喷

      1 #include <cstdio>
      2 #include <cmath>
      3 #include <cstring>
      4 #include <algorithm>
      5 using namespace std;
      6 int n,m,x,y,N;
      7 int a[200001],b[200001];//未排序数据和已排序数据 
      8 int l[2000],r[2000];//分块两端 
      9 //处理重复数据真TM的累,find和Find带_的是找小于给定关键字的数的个数的,不带的是找大于的个数的
     10 int Find(int o,int x)//在一块中二分查找x 
     11 {
     12     int L=l[o],R=r[o];
     13     while(L<R-1)
     14     {
     15         int mid=(L+R)/2;
     16         if(b[mid]<=x)//这边一开始缺个等号导致我调一下午
     17             L=mid;
     18         else
     19             R=mid;
     20     }
     21     if(b[R]<=x)
     22         return r[o]-R;
     23     else
     24     if(x<b[L])
     25         return r[o]-L+1;
     26     else
     27         return r[o]-L;
     28 }
     29 int find(int x,int y,int z)//查询,分成三段分别求解
     30 {
     31     int sum=0;
     32     for(int i=1;i<=N;i++)
     33         if((x<=l[i])&&(r[i]<=y))
     34             sum+=Find(i,z);
     35         else
     36         if((x>=l[i])&&(y<=r[i]))
     37         {
     38             for(int j=x;j<=y;j++)
     39                 sum+=a[j]>z;
     40             return sum;
     41         }
     42         else
     43         if(x>=l[i] && x<=r[i])
     44             for(int j=x;j<=r[i];j++)
     45                 sum+=a[j]>z;
     46         else
     47         if(l[i]<=y && y<=r[i])
     48         {
     49             for(int j=l[i];j<=y;j++)
     50                 sum+=a[j]>z;
     51             return sum;
     52         }
     53     return sum;
     54 }
     55 int _Find(int o,int x)//在一块中二分查找x 
     56 {
     57     int L=l[o],R=r[o];
     58     while(L<R-1)
     59     {
     60         int mid=(L+R)/2;
     61         if(b[mid]<x)//这边不能有等号,非常神奇,建议想一想为什么
     62             L=mid;
     63         else
     64             R=mid;
     65     }
     66     if(b[R]<x)
     67         return R-l[o]+1;
     68     else
     69     if(x<=b[L])
     70         return L-l[o];
     71     else
     72         return R-l[o];
     73 }
     74 int _find(int x,int y,int z)//查询,分成三段分别求解 
     75 {
     76     int sum=0;
     77     for(int i=1;i<=N;i++)
     78         if((x<=l[i])&&(r[i]<=y))
     79             sum+=_Find(i,z);
     80         else
     81         if((x>=l[i])&&(y<=r[i]))
     82         {
     83             for(int j=x;j<=y;j++)
     84                 sum+=a[j]<z;
     85             return sum;
     86         }
     87         else
     88         if(x>=l[i] && x<=r[i])
     89             for(int j=x;j<=r[i];j++)
     90                 sum+=a[j]<z;
     91         else
     92         if(l[i]<=y && y<=r[i])
     93         {
     94             for(int j=l[i];j<=y;j++)
     95                 sum+=a[j]<z;
     96             return sum;
     97         }
     98     return sum;
     99 }
    100 void change(int x,int y)//把位于x的数改成y,冒个泡 
    101 {
    102     int i,j;
    103     for(i=1;r[i]<x;i++);
    104     for(j=l[i];b[j]!=a[x];j++);
    105     b[j]=y;
    106     while((j<r[i])&&(b[j]>b[j+1]))
    107     {
    108         swap(b[j],b[j+1]);
    109         j++;
    110     }
    111     while((j>l[i])&&(b[j]<b[j-1]))
    112     {
    113         swap(b[j],b[j-1]);
    114         j--;
    115     }
    116     a[x]=y;
    117 }
    118 int init()//预处理,分块+排序 
    119 {
    120     int sq=(int)sqrt(n);
    121     for(int i=1;i<=sq;i++)
    122     {
    123         l[i]=sq*(i-1)+1;
    124         r[i]=sq*i;
    125     }
    126     if(sq*sq<n)
    127     {
    128         l[sq+1]=sq*sq+1;
    129         r[++sq]=n;
    130     }
    131     memcpy(b,a,sizeof(a));
    132     for(int i=1;i<=sq;i++)
    133         sort(b+l[i],b+r[i]+1);
    134     return sq;
    135 }
    136 int main()
    137 {
    138     scanf("%d",&n);
    139     for(int i=1;i<=n;i++)
    140         scanf("%d",&a[i]);
    141     N=init();
    142     int ans=0;
    143     for(int i=1;i<n;i++)
    144         ans+=_find(i+1,n,a[i]);
    145     printf("%d
    ",ans);
    146     scanf("%d",&m);
    147     for(int i=1;i<=m;i++)
    148     {
    149         scanf("%d%d",&x,&y);
    150         if(x>y)
    151             swap(x,y);
    152         ans-=find(x,y-1,a[y]);
    153         ans+=_find(x,y-1,a[y]);
    154         if(y-x>1)
    155         {
    156             ans+=find(x+1,y-1,a[x]);
    157             ans-=_find(x+1,y-1,a[x]);
    158         }
    159         printf("%d
    ",ans);
    160         int t=a[x];
    161         change(x,a[y]);
    162         change(y,t);
    163     }
    164     return 0;
    165 }

    据说一个函数不能太长,否则难看,于是就瞎写成了这副德行%还是不习惯啊

  • 相关阅读:
    函数式宏定义与普通函数
    linux之sort用法
    HDU 4390 Number Sequence 容斥原理
    HDU 4407 Sum 容斥原理
    HDU 4059 The Boss on Mars 容斥原理
    UVA12653 Buses
    UVA 12651 Triangles
    UVA 10892
    HDU 4292 Food
    HDU 4288 Coder
  • 原文地址:https://www.cnblogs.com/wanglichao/p/5650670.html
Copyright © 2011-2022 走看看