• 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 }

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

  • 相关阅读:
    ege demo
    Easy Graphics Engine vs2015使用
    c++ demo
    leetcode 13 -> Roman to Integer
    leetcode 12 -> Integer to Roman
    12. Integer to Roman
    leetcode 9 -> Palindrome Number
    8. String to Integer (atoi)
    获取字符串中长度最长的回文字符串
    leetcode 5-> Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/wanglichao/p/5650670.html
Copyright © 2020-2023  润新知