zoukankan      html  css  js  c++  java
  • 【分块】【树套树】bzoj2141 排队

    考虑暴力更新的情况,设swap的是L,R位置的数。
    swap之后的逆序对数应该等于:
    之前的逆序对数
    +[L+1,R-1]中比 L位置的数 大的数的个数
    -[L+1,R-1]中比 L位置的数 小的数的个数
    -[L+1,R-1]中比 R位置的数 大的数的个数
    +[L+1,R-1]中比 R位置的数 小的数的个数

    并且若L位置的数>R位置的数,逆序对数--;反之,逆序对数++。

    分块,对每个块内部进行sort,这样可以二分,在O(log(sqrt(n))的时间内求得某个块内比某个数大/小的数的个数。所以每次更新是O(sqrt(n)*log(sqrt(n))的。
    若L和R所在的块相同或相邻时,直接暴力更新即可。

    要用树状数组或归并排序求得初始答案。

    要注意数据是可重的,所以要打时间戳。
    所以为了lower_bound/upper_bound,要定义两套比较法则,一套双关键字,一套单关键字。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cmath>
     4 using namespace std;
     5 struct Point{int v,p;Point(const int &a,const int &b){v=a;p=b;}Point(){}};
     6 bool operator < (const Point &a,const Point &b){return a.v<b.v;}//单关键字比较 
     7 bool operator > (const Point &a,const Point &b){return a.v>b.v;}
     8 bool operator == (const Point &a,const Point &b){return a.v==b.v ? true : false;}
     9 bool cmp(const Point &a,const Point &b){return a.v!=b.v ? a.v<b.v : a.p<b.p;}//双关键字比较 
    10 Point b[20001],a[20001],c[20001];
    11 int n,sz,l[145],r[145],sum,num[20001],ans,x,y,m,mid,en;
    12 int Res,Num;char C,CH[20];
    13 inline int G()
    14 {
    15     Res=0;C='*'; 
    16     while(C<'0'||C>'9')C=getchar();
    17     while(C>='0'&&C<='9'){Res=Res*10+(C-'0');C=getchar();}
    18     return Res;
    19 }
    20 inline void P(int x)
    21 {
    22     if(!x){putchar('0');putchar('
    ');return;}
    23     Num=0;while(x>0)CH[++Num]=x%10,x/=10;
    24     while(Num)putchar(CH[Num--]+48);
    25     putchar('
    ');
    26 }
    27 void LiSan()
    28 {
    29     n=G();
    30     for(int i=1;i<=n;i++){b[i].v=G();b[i].p=i;}
    31     sort(b+1,b+n+1,cmp);
    32     for(int i=1;i<=n;i++)
    33       {
    34           if(b[i].v!=b[i-1].v)en++;
    35         a[b[i].p].v=en;
    36         a[b[i].p].p=i;
    37       }
    38 }
    39 //树状数组求出初始答案。 
    40 int D[20001];inline int lowbit(const int &x){return x&(-x);}
    41 inline int getsum(int x){int res=0;while(x>0){res+=D[x];x-=lowbit(x);}return res;}
    42 inline void add(int x,const int &d){while(x<=n){D[x]+=d;x+=lowbit(x);}}
    43 void Get_First_Ans()
    44 {for(int i=1;i<=n;i++){add(a[i].v,1);ans+=(i-getsum(a[i].v));}
    45 P(ans);}
    46 void makeblock()
    47 {
    48     sz=sqrt(n);
    49     for(sum=1;sum*sz<n;sum++)
    50       {
    51         l[sum]=(sum-1)*sz+1;r[sum]=sum*sz;
    52           for(int i=l[sum];i<=r[sum];i++)
    53           num[i]=sum;
    54       }
    55     l[sum]=sz*(sum-1)+1;r[sum]=n;
    56     for(int i=l[sum];i<=r[sum];i++)
    57       num[i]=sum;
    58 }
    59 void Sort_Each_Block()
    60 {for(int i=1;i<=n;i++)c[i]=a[i];
    61 for(int i=1;i<=sum;i++)sort(a+l[i],a+r[i]+1,cmp);}
    62 inline int Query(const int &L,const int &R)
    63 {
    64     swap( a[lower_bound(a+l[num[L]],a+r[num[L]]+1,c[L],cmp) - a ]
    65     , a[lower_bound(a+l[num[R]],a+r[num[R]]+1,c[R],cmp)- a ]);//必须双关键字比较 
    66     sort(a+l[num[L]],a+r[num[L]]+1,cmp);
    67     sort(a+l[num[R]],a+r[num[R]]+1,cmp);
    68     int cnt=0;
    69     if(c[L].v<c[R].v)cnt=1;
    70     else if(c[L].v>c[R].v)cnt=-1;
    71     swap(c[L],c[R]);
    72     if(num[L]+1>=num[R])
    73       for(int i=L+1;i<=R-1;i++)
    74           {if(c[i].v>c[R].v)cnt++;else if(c[i].v<c[R].v)cnt--;
    75            if(c[i].v>c[L].v)cnt--;else if(c[i].v<c[L].v)cnt++;}
    76     else
    77       {
    78           for(int i=L+1;i<=r[num[L]];i++)
    79             {if(c[i].v>c[R].v)cnt++;else if(c[i].v<c[R].v)cnt--;
    80              if(c[i].v>c[L].v)cnt--;else if(c[i].v<c[L].v)cnt++;}
    81           for(int i=l[num[R]];i<=R-1;i++)
    82             {if(c[i].v>c[R].v)cnt++;else if(c[i].v<c[R].v)cnt--;
    83              if(c[i].v>c[L].v)cnt--;else if(c[i].v<c[L].v)cnt++;}
    84           for(int i=num[L]+1;i<=num[R]-1;i++)
    85             {
    86                 cnt+=( (a+r[i]+1) - upper_bound(a+l[i],a+r[i]+1,c[R]) );//必须单关键字比较 
    87                 cnt-=( lower_bound(a+l[i],a+r[i]+1,c[R]) - (a+l[i]) );
    88             cnt-=( (a+r[i]+1) - upper_bound(a+l[i],a+r[i]+1,c[L]) );
    89             cnt+=( lower_bound(a+l[i],a+r[i]+1,c[L]) - (a+l[i]) );
    90             }
    91       }
    92     ans+=cnt;return ans;
    93 }
    94 int main()
    95 {
    96     LiSan();Get_First_Ans();makeblock();Sort_Each_Block();m=G();
    97     for(int i=1;i<=m;i++){x=G();y=G();if(x>y)swap(x,y);P(Query(x,y));}
    98     return 0;
    99 }
    ——The Solution By AutSky_JadeK From UESTC 转载请注明出处:http://www.cnblogs.com/autsky-jadek/
  • 相关阅读:
    ColorPix——到目前为止最好用的屏幕取色器
    ES+VBA 实现批量添加网络图片
    SQL语句-delete语句
    Visual C++ 2013 and Visual C++ Redistributable Package 更新版官网下载地址
    centos长ping输出日志的脚本
    Centos 常用命令
    c#连接数据库
    C#窗体间的跳转传值
    c#邮件发送
    C#WIFI搜索与连接
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/3968451.html
Copyright © 2011-2022 走看看