zoukankan      html  css  js  c++  java
  • BZOJ3295 [Cqoi2011]动态逆序对 —— CDQ分治

    题目链接:https://vjudge.net/problem/HYSBZ-3295

    3295: [Cqoi2011]动态逆序对

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 6517  Solved: 2295
    [Submit][Status][Discuss]

    Description

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

    Input

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

    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)。

    题解:

    1.最核心的问题是:删除当前位置的数,会造成多少对逆序对的减少。

    2.要统计删除当前数会造成多少对逆序对的减少,即需要统计:前面比它大的数的个数 + 后面比它小的数的个数 (前提是这些数没有被删除)。

    3.由于题目还存在动态删除,则再为每个位置添加一个标志:Di,表明它是第几个被删除的。加上这个限制,就是一个三维偏序问题了。

    4.以j为统计对象,sum[j]为删除位置j的数,所减少的逆序对。sum[j] = sum (i<j 且 Ai>Aj 且 Di>Dj)+ (j<i 且 Aj>Ai 且 Di>Dj)

    5.得到sum数组之后,即知道删除当前位置的数,会造成多少对逆序对的减少。那么再算出初始的逆序对(不带删除,即二维偏序)即可。

    写法一:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <cmath>
      7 #include <queue>
      8 #include <stack>
      9 #include <map>
     10 #include <string>
     11 #include <set>
     12 using namespace std;
     13 typedef long long LL;
     14 const int INF = 2e9;
     15 const LL LNF = 9e18;
     16 const int MOD = 1e9+7;
     17 const int MAXN = 1e5+100;
     18 
     19 struct node
     20 {
     21     int x, y, z;
     22 };
     23 node a[MAXN], b[MAXN], tmp[MAXN];
     24 
     25 int n, m, c[MAXN];
     26 int lowbit(int x) {return x&(-x);}
     27 void add(int x, int val) {for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val;}
     28 int query(int x) {int ret=0; for(int i=x;i>0;i-=lowbit(i))ret+=c[i]; return ret;}
     29 
     30 int sum[MAXN], type;
     31 void CDQ(int l, int r)
     32 {
     33     if(l==r) return;
     34 
     35     int mid = (l+r)>>1;
     36     CDQ(l, mid); CDQ(mid+1, r);
     37     int p1 = l, p2 = mid+1;
     38     for(int i = l; i<=r; i++)
     39     {
     40         if(p2>r||(p1<=mid&&a[p1].y>=a[p2].y)) b[i] = a[p1++];
     41         else b[i] = a[p2++];
     42     }
     43     int cnt = 0;    //按删除顺序逆序排序了,所以先出现的更后删除
     44     for(int i = l; i<=r; i++)   //统计前面比它小的
     45     {
     46         a[i] = b[i];
     47         if(a[i].x<=mid) add(a[i].z, 1), cnt++;
     48         else if(a[i].y!=INF) sum[a[i].y] += cnt-query(a[i].z);
     49     }
     50     for(int i = l; i<=r; i++)
     51         if(a[i].x<=mid) add(a[i].z, -1);
     52 
     53     for(int i = l; i<=r; i++)   //统计后面比它大的
     54     {
     55         a[i] = b[i];
     56         if(a[i].x>mid) add(a[i].z, 1);
     57         else if(a[i].y!=INF) sum[a[i].y] += query(a[i].z-1);
     58     }
     59     for(int i = l; i<=r; i++)
     60         if(a[i].x>mid) add(a[i].z, -1);
     61 }
     62 
     63 int M[MAXN];
     64 int main()
     65 {
     66     while(scanf("%d%d", &n,&m)!=EOF)
     67     {
     68         for(int i = 1; i<=n; i++)
     69         {
     70             scanf("%d", &a[i].z);
     71             M[a[i].z] = i;
     72             a[i].x = i; a[i].y = INF;
     73         }
     74         for(int i = 1; i<=m; i++)
     75         {
     76             int del;
     77             scanf("%d", &del);
     78             a[M[del]].y = i;
     79         }
     80 
     81         LL ans = 0;
     82         memset(c, 0, sizeof(c));
     83         for(int i = 1; i<=n; i++)
     84         {
     85             ans += (i-1)-query(a[i].z);
     86             add(a[i].z, 1);
     87         }
     88 
     89         memset(c, 0, sizeof(c));
     90         memset(sum, 0, sizeof(sum));
     91         CDQ(1,n);
     92 
     93         printf("%lld
    ", ans);
     94         for(int i = 1; i<m; i++)
     95         {
     96             ans -= sum[i];
     97             printf("%lld
    ", ans);
     98         }
     99     }
    100 }
    View Code

    写法二:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <cmath>
      7 #include <queue>
      8 #include <stack>
      9 #include <map>
     10 #include <string>
     11 #include <set>
     12 using namespace std;
     13 typedef long long LL;
     14 const int INF = 2e9;
     15 const LL LNF = 9e18;
     16 const int MOD = 1e9+7;
     17 const int MAXN = 1e5+100;
     18 
     19 struct node
     20 {
     21     int x, y, z;
     22 };
     23 node a[MAXN], b[MAXN];
     24 
     25 int n, m, c[MAXN];
     26 int lowbit(int x) {return x&(-x);}
     27 void add(int x, int val) {for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val;}
     28 int query(int x) {int ret=0; for(int i=x;i>0;i-=lowbit(i))ret+=c[i]; return ret;}
     29 
     30 int sum[MAXN], type;
     31 void CDQ(int l, int r)
     32 {
     33     if(l==r) return;
     34 
     35     int mid = (l+r)>>1;
     36     CDQ(l, mid); CDQ(mid+1, r);
     37     int p1 = l, p2 = mid+1;
     38     for(int i = l; i<=r; i++)
     39     {
     40         if(p2>r||(p1<=mid&&a[p1].y>=a[p2].y)) b[i] = a[p1++];
     41         else b[i] = a[p2++];
     42     }
     43     int cnt = 0;
     44     for(int i = l; i<=r; i++)
     45     {
     46         a[i] = b[i];
     47         if(a[i].x<=mid) add(a[i].z, 1), cnt++;
     48         else if(a[i].y!=INF)
     49         {
     50             if(type) sum[a[i].y] += cnt-query(a[i].z);
     51             else sum[a[i].y] += query(a[i].z-1);
     52         }
     53     }
     54     for(int i = l; i<=r; i++)
     55         if(a[i].x<=mid) add(a[i].z, -1);
     56 }
     57 
     58 node tmp[MAXN];
     59 int M[MAXN];
     60 int main()
     61 {
     62     while(scanf("%d%d", &n,&m)!=EOF)
     63     {
     64         for(int i = 1; i<=n; i++)
     65         {
     66             scanf("%d", &a[i].z);
     67             M[a[i].z] = i;
     68             a[i].y = INF;
     69         }
     70         for(int i = 1; i<=m; i++)
     71         {
     72             int del;
     73             scanf("%d", &del);
     74             a[M[del]].y = i;
     75         }
     76 
     77         LL ans = 0;
     78         memset(c, 0, sizeof(c));
     79         for(int i = 1; i<=n; i++)
     80         {
     81             ans += (i-1)-query(a[i].z);
     82             add(a[i].z, 1);
     83         }
     84 
     85         memcpy(tmp, a, sizeof(tmp));
     86         for(int i = 1; i<=n; i++)
     87             a[i].x = i;
     88         memset(c, 0, sizeof(c));
     89         type = 1;
     90         CDQ(1,n);
     91 
     92         memcpy(a, tmp, sizeof(a));
     93         reverse(a+1,a+1+n);
     94         for(int i = 1; i<=n; i++)
     95             a[i].x = i;
     96         type = 0;
     97         CDQ(1,n);
     98 
     99         printf("%lld
    ", ans);
    100         for(int i = 1; i<m; i++)
    101         {
    102             ans -= sum[i];
    103             printf("%lld
    ", ans);
    104         }
    105     }
    106 }
    View Code
  • 相关阅读:
    Oracle11g 审计介绍
    用Go向MySQL导入.csv文件
    【Lucene】实现全文索引
    redis-3.0.1 sentinel 主从高可用 详细配置
    MySQL性能优化之max_connections配置
    数据结构算法
    inux 软件编译、安装、删除
    2015年,才开始流行的几个教育观念
    常见的几种语言函数调用约定
    关于代码调试de那些事
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8660591.html
Copyright © 2011-2022 走看看