• [CQOI2011]动态逆序对


    P1347 - [CQOI2011]动态逆序对

    Description

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

    Input

    输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。
    以下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

    Hint

    样例解释
    (1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
    数据规模:
    N<=100000 , M<=50000

    把删除看成插入,将每个点赋予一个插入时间,则i的逆序对要满足的条件为:
    位置在i前,值比i大,时间比i小;或者位置在i后,值比i小,时间比i小。
    然后就可以用
    sort+CDQ+树状数组维护三维偏序,注意每个时间的答案要加上前面时间的答案。
      1 #include<set>
      2 #include<map>
      3 #include<queue>
      4 #include<stack>
      5 #include<ctime>
      6 #include<cmath>
      7 #include<string>
      8 #include<vector>
      9 #include<cstdio>
     10 #include<cstdlib>
     11 #include<cstring>
     12 #include<iostream>
     13 #include<algorithm>
     14 #define maxn 100010
     15 using namespace std;
     16 struct data{
     17   int x,y,z,ans1,ans2;
     18 }f[maxn];
     19 int tree[maxn],co[maxn],LOL=0;
     20 long long ans[maxn];
     21 int lowbit(int x){return x&-x;}
     22 void add(int p,int v){
     23   for(int i=p;i<maxn;i+=lowbit(i)){
     24     if(co[i]!=LOL) tree[i]=0;
     25     co[i]=LOL;
     26     tree[i]+=v;
     27   }
     28 }
     29 int find(int p){
     30   int ret=-0;
     31   for(int i=p;i;i-=lowbit(i))
     32     if(co[i]==LOL) ret+=tree[i];
     33   return ret;
     34 }
     35 bool cmpcdq1(const data &a,const data &b){
     36   if(a.y!=b.y) return a.y>b.y;
     37   else return a.z<b.z;
     38 }
     39 bool cmpcdq2(const data &a,const data &b){
     40   if(a.y!=b.y) return a.y<b.y;
     41   else return a.z<b.z;
     42 }
     43 void CDQ1(int l,int r){
     44   if(l==r) return;
     45   int mid=(l+r)>>1;
     46   CDQ1(l,mid),CDQ1(mid+1,r);
     47   sort(f+l,f+mid+1,cmpcdq1),sort(f+mid+1,f+r+1,cmpcdq1);
     48   LOL++;
     49   for(int j=mid+1,i=l;j<=r;j++){
     50     for(;f[i].y>f[j].y&&i<=mid;i++)
     51       add(f[i].z,1);
     52     f[j].ans1+=find(f[j].z);
     53   }
     54 }
     55 void CDQ2(int l,int r){
     56   if(l==r) return;
     57   int mid=(l+r)>>1;
     58   CDQ2(l,mid),CDQ2(mid+1,r);
     59   sort(f+l,f+mid+1,cmpcdq2),sort(f+mid+1,f+r+1,cmpcdq2);
     60   LOL++;
     61   for(int j=mid+1,i=l;j<=r;j++){
     62     for(;f[i].y<f[j].y&&i<=mid;i++)
     63       add(f[i].z,1);
     64     f[j].ans2+=find(f[j].z);
     65   }
     66 }
     67 bool cmmp(const data &a,const data &b){
     68   return a.y<b.y;
     69 }
     70 bool cmmmp(const data &a,const data &b){
     71   return a.x<b.x;
     72 }
     73 bool cmmmp1(const data &a,const data &b){
     74   return a.x>b.x;
     75 }
     76 int main()
     77 {
     78   freopen("!.in","r",stdin);
     79   freopen("!.out","w",stdout);
     80   int n,m,sp;scanf("%d%d",&n,&m);
     81   for(int i=1;i<=n;i++)
     82     scanf("%d",&f[i].y),f[i].x=i;
     83   sort(f+1,f+n+1,cmmp);
     84   int cnt=m+1;
     85   for(int i=1;i<=m;i++)
     86     scanf("%d",&sp),f[sp].z=cnt,cnt--;
     87   for(int i=1;i<=n;i++)
     88     if(!f[i].z)f[i].z=1;
     89   sort(f+1,f+n+1,cmmmp);
     90   CDQ1(1,n);
     91   LOL=0;memset(co,0,sizeof(co));
     92   sort(f+1,f+n+1,cmmmp1);
     93   CDQ2(1,n);
     94   for(int i=1;i<=n;i++)
     95     ans[f[i].z]+=f[i].ans1+f[i].ans2;
     96   ans[1]/=2;
     97   for(int i=2;i<=m+1;i++)
     98     ans[i]+=ans[i-1];
     99   for(int i=m+1;i>=2;i--)
    100     printf("%lld
    ",ans[i]);
    101   return 0;
    102 }
    
    
    
     
  • 相关阅读:
    linux学习网站
    异步JS(Asynchronous JavaScript)
    针对性的遍历tree数据,获取所需要的内容(获取id数组、id对应的层级数组、来获取当前的对象)
    代码注释中的专有词:TODO、FIXME和XXX
    四月份前端面试指北
    微信小程序之裁剪图片成圆形
    金九银十求职季,前端面试大全送给你
    node:爬虫爬取网页图片
    微信小程序UI组件库 iView Weapp快速上手
    (干货)微信小程序之转发好友
  • 原文地址:https://www.cnblogs.com/pantakill/p/6657803.html
Copyright © 2020-2023  润新知