zoukankan      html  css  js  c++  java
  • Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对

    3295: [Cqoi2011]动态逆序对

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 2886  Solved: 924
    [Submit][Status][Discuss]

    Description

    对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

    Input

    输入第一行包含两个整数nm,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
     

    Output

     
    输出包含m行,依次为删除每个元素之前,逆序对的个数。

    Sample Input

    5 4
    1
    5
    3
    4
    2
    5
    1
    4
    2

    Sample Output

    5
    2
    2
    1

    样例解释
    (1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

    HINT

    N<=100000 M<=50000

    Source

     题解:
    分块+树状数组+逆序对
    好像正解是CDQ分治 QAQ
    然而不会。。。
    胡搞了一个分块,记录一下每个数出现的位置。然后,考虑到每次删除,对答案有影响的只有当前这个数前头比它大的个数,和后头比他小的个数。所以就分块统计有多少个。但是,如何删除呢?
    我是在更新完答案后,把当前的这个数放成-1。然后对于统计这个数前头比它大的数的个数没有影响(因为-1比任何数都小,不会被统计上)。但对于后头比它小的个数就不一样了。但,-1比任何数都小,所以它一定在每个排好序的块的最前端的一段。我们只需要二分去找第一个不是-1的位置,然后就可以统计了。(各种二分。。。)
    至于速度嘛,rank榜上倒数。。。QAQ赶快去学CDQ分治。。。
      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define MAXN 100010
      4 #define LL long long
      5 int pos[MAXN],BIT[MAXN],a[MAXN],b[MAXN],wz[MAXN],block,n;
      6 LL ans;
      7 int read()
      8 {
      9     int s=0,fh=1;char ch=getchar();
     10     while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
     11     while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
     12     return s*fh;
     13 }
     14 int Lowbit(int o){return o&(-o);}
     15 void Update(int o,int o1)
     16 {
     17     while(o<=n)
     18     {
     19         BIT[o]+=o1;
     20         o+=Lowbit(o);
     21     }
     22 }
     23 int Sum(int o)
     24 {
     25     int sum=0;
     26     while(o>0)
     27     {
     28         sum+=BIT[o];
     29         o-=Lowbit(o);
     30     }
     31     return sum;
     32 }
     33 void cl(int k)
     34 {
     35     int l=(k-1)*block+1,r=min(k*block,n),i;
     36     for(i=l;i<=r;i++)b[i]=a[i];
     37     sort(b+l,b+r+1);
     38 }
     39 int ef(int k,int k1)//在第k块中寻找大于k1的第一个位置.
     40 {
     41     int l=(k-1)*block+1,r=min(k*block,n),ans1;
     42     ans1=-1;
     43     while(l<=r)
     44     {
     45         int mid=(l+r)/2;
     46         if(b[mid]>k1){ans1=mid;r=mid-1;}
     47         else l=mid+1;
     48     }
     49     return ans1;
     50 }
     51 int ef1(int k,int k1)
     52 {
     53     int l=(k-1)*block+1,r=min(k*block,n),ans1;
     54     ans1=-1;
     55     while(l<=r)
     56     {
     57         int mid=(l+r)/2;
     58         if(b[mid]<k1){ans1=mid;l=mid+1;}
     59         else r=mid-1;
     60     }
     61     return ans1;
     62 }
     63 void calc1(int l,int r,int D)
     64 {
     65     if(l>r)return;
     66     int L=pos[l],R=pos[r],i,pd;
     67     if(L==R)
     68     {
     69         for(i=l;i<=r;i++)if(a[i]>D&&a[i]!=-1)ans--;
     70         return;
     71     }
     72     for(i=l;i<=L*block;i++)if(a[i]>D&&a[i]!=-1)ans--;
     73     for(i=L+1;i<=R-1;i++)
     74     {
     75         pd=ef(i,D);
     76         if(pd!=-1)ans-=(LL)(min(i*block,n)-pd+1);
     77     }
     78     //ans-=(ef(i,D)-ef(i,0)+1);
     79     for(i=(R-1)*block+1;i<=r;i++)if(a[i]>D&&a[i]!=-1)ans--;
     80 }
     81 void calc2(int l,int r,int D)
     82 {
     83     if(l>r)return;
     84     int L=pos[l],R=pos[r],i,pd,pd1;
     85     if(L==R)
     86     {
     87         for(i=l;i<=r;i++)if(a[i]<D&&a[i]!=-1)ans--;
     88         return;
     89     }
     90     for(i=l;i<=L*block;i++)if(a[i]<D&&a[i]!=-1)ans--;
     91     for(i=L+1;i<=R-1;i++)
     92     {
     93         //ans-=(ef1(i,D)-ef(i,0)+1);
     94         pd=ef1(i,D);
     95         if(b[pd]!=-1)
     96         {
     97             pd1=ef(i,0);
     98             if(pd!=-1)
     99             {
    100                 if(pd1==-1)pd1=1;
    101                 ans-=(LL)(pd-pd1+1);
    102             }
    103         }
    104     }
    105     for(i=(R-1)*block+1;i<=r;i++)if(a[i]<D&&a[i]!=-1)ans--;
    106 }
    107 int main()
    108 {
    109     freopen("inverse.in","r",stdin);
    110     freopen("inverse.out","w",stdout);
    111     int m,i,M,del;
    112     n=read();m=read();
    113     for(i=1;i<=n;i++)a[i]=read(),wz[a[i]]=i;
    114     block=(int)sqrt(n);
    115     for(i=1;i<=n;i++)pos[i]=(int)(i-1)/block+1;
    116     if(n%block==0)M=n/block;
    117     else M=n/block+1;
    118     memset(BIT,0,sizeof(BIT));ans=0;
    119     for(i=n;i>=1;i--)
    120     {
    121         ans+=Sum(a[i]-1);
    122         Update(a[i],1);
    123     }
    124     for(i=1;i<=M;i++)cl(i);
    125     for(i=1;i<=m;i++)
    126     {
    127         del=read();
    128         printf("%lld
    ",ans);
    129         calc1(1,wz[del]-1,del);//去寻找 从位置1到要删除的数前一个位置 中有多少个数大于要删除的数,并把个数减去.
    130         calc2(wz[del]+1,n,del);//去寻找 从要删除的数后一个位置到位置n 中有多少个数小于要删除的数,并把个数减去.
    131         a[wz[del]]=-1;
    132         cl(pos[wz[del]]);
    133         //printf("%d
    ",ans);
    134     }
    135     fclose(stdin);
    136     fclose(stdout);
    137     return 0;
    138 }
  • 相关阅读:
    textarea宽度、高度自动适应处理方法
    Table嵌套去掉子table的外边框
    发现原来自己挺能给自己找理由开脱的
    Life is not the amount of breath you take.
    在遍历ResultSet的循环中再执行SQL会发生什么(前提:同一个Statement)
    按月查询数据
    Oracle SQL 判断某表是否存在
    在Python程序中执行linux命令
    在Oracle中十分钟内创建一张千万级别的表
    Redis Sentinel结构 及相关文档
  • 原文地址:https://www.cnblogs.com/Var123/p/5337309.html
Copyright © 2011-2022 走看看