[CQOI2011]动态逆序对

Posted turkeyghb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CQOI2011]动态逆序对相关的知识,希望对你有一定的参考价值。

[CQOI2011]动态逆序对

 

时间限制:2 s   内存限制:128 MB

【题目描述】

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

【输入格式】

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

【输出格式】

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

【样例输入】

5 4
  1
  5
  3
  4
  2
  5
  1
  4
  2
  

【样例输出】

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

【提示】

 

N<=100000 M<=50000

 

【来源】

 

【题目来源】

耒阳大世界(衡阳八中) OJ 3295

 

 

 

三维的cdq分治,对每一个点额外记录一个变量来表示他的删除时间,为了后面树状数组的操作方便,我们反过来维护,即维护其“插入时间”,看做是由最终状态插入得到的,那么问题就转换成了,每插入一个数,就求出这个数和早于他插入的数字构成的逆序对数。这道题需要同时计算左边对右边的影响和右边对左边的影响,但是没被删除的也就是我代码中插入时间为1的那些数字,他们所构成的逆序对数会被计算两次,所以要除二,那么最终求得的数组就表示的每次插入数字所形成的逆序对数,求一下前缀和输出即可。

技术分享图片
  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 using namespace std;
  4 const int maxn=1e5+10;
  5 int n,m,hs[maxn],s[maxn];
  6 ll ans[maxn];
  7 int read(){
  8     int a=0;
  9     char ch=getchar();
 10     while(!(ch<=9&&ch>=0))ch=getchar();
 11     while(ch<=9&&ch>=0){
 12         a=(a<<1)+(a<<3)+(ch^0);
 13         ch=getchar();
 14     }
 15     return a;
 16 }
 17 struct number{
 18     int val,tim;
 19 }q[maxn],tmp[maxn];
 20 int lowbit(int x){
 21     return x&(-x);
 22 }
 23 void add(int x){
 24     for(int i=x;i<=m+1;i+=lowbit(i))s[i]++;
 25 }
 26 int sum(int x){
 27     int t=0;
 28     for(int i=x;i;i-=lowbit(i))t+=s[i];
 29     return t;
 30 }
 31 void clear(int x){
 32     for(int i=x;i<=m+1;i+=lowbit(i)){
 33         if(s[i])s[i]=0;
 34         else break;
 35     }
 36 }
 37 void cdq(int l,int r){
 38     if(l==r)return ;
 39     int mid=(l+r)>>1;
 40     cdq(l,mid);cdq(mid+1,r);
 41     int o,p1=l,p2=mid+1;
 42     while(p1<=mid&&p2<=r){
 43         if(q[p1].val>q[p2].val){
 44             add(q[p1].tim);
 45             p1++;
 46         }
 47         else {
 48             ans[q[p2].tim]+=sum(q[p2].tim);
 49             p2++;
 50         }
 51     }
 52     while(p2<=r){
 53         ans[q[p2].tim]+=sum(q[p2].tim);
 54         p2++;
 55     }
 56     for(int i=l;i<=p1;i++)clear(q[i].tim);
 57     p1=mid,p2=r,o=r+1;
 58     while(p1>=l&&p2>=mid+1){
 59         if(q[p1].val>q[p2].val){
 60             add(q[p2].tim);
 61             tmp[--o]=q[p2--];
 62         }
 63         else {
 64             ans[q[p1].tim]+=sum(q[p1].tim);
 65             tmp[--o]=q[p1--];
 66         }
 67     }
 68     while(p1>=l){
 69         ans[q[p1].tim]+=sum(q[p1].tim);
 70         tmp[--o]=q[p1--];
 71     }
 72     while(p2>=mid+1)tmp[--o]=q[p2--];
 73     for(int i=l;i<=r;i++){
 74         clear(q[i].tim);
 75         q[i]=tmp[i];
 76     }
 77 }
 78 void out(ll x){
 79     if(x/10)out(x/10);
 80     putchar(0+x%10);
 81 }
 82 int main()
 83 {
 84     freopen("inverse.in","r",stdin);
 85     freopen("inverse.out","w",stdout);
 86     n=read();m=read();
 87     for(int i=1;i<=n;i++){
 88         q[i].val=read();
 89         hs[q[i].val]=i;
 90         q[i].tim=1;
 91     }
 92     for(int i=1;i<=m;i++){
 93         int x;
 94         x=read();
 95         q[hs[x]].tim=m-i+2;
 96     }
 97     cdq(1,n);
 98     ans[1]/=2;
 99     for(int i=2;i<=m+1;i++)ans[i]+=ans[i-1];
100     for(int i=m+1;i>=2;i--){
101         out(ans[i]);
102         putchar(\n);
103     }
104     return 0;
105 }
View Code

 

以上是关于[CQOI2011]动态逆序对的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3295: [Cqoi2011]动态逆序对

[CQOI2011]动态逆序对

BZOJ 3295: [Cqoi2011]动态逆序对 cdq分治

[BZOJ3295][Cqoi2011]动态逆序对

[CQOI2011]动态逆序对

bzoj3295: [Cqoi2011]动态逆序对