zoukankan      html  css  js  c++  java
  • 【BZOJ3295】【块状链表+树状数组】动态逆序对

    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

    【分析】

    这种水题还弄了两节课...真是没法治了。

    用很多种方法,最好理解的就是块状链表套树状数组,每个块状链表里面套一个二维的树状数组,再加上离散化。

    将m序列中的每一个数字对应一个坐标(在n中坐标,n-数字大小)然后就可以做了。

    我还开了3个一维树状数组,卡着时间过的。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <vector>
      6 #include <utility>
      7 #include <iomanip>
      8 #include <string>
      9 #include <cmath>
     10 #include <queue>
     11 #include <assert.h>
     12 #include <map>
     13 
     14 const int N = 100000 + 10;
     15 const int SIZE = 225;//块状链表的根号50000 
     16 const int M = 50000 + 5;
     17 using namespace std;
     18 typedef long long ll;
     19 int lowbit(int x) {return x & -x;}
     20 struct BLOCK_LIST{
     21      int C[SIZE][SIZE];
     22      int t[2][SIZE];//关于a的离散化序列和b的离散化序列 
     23      void init(){
     24           memset(C, 0, sizeof(C));
     25           memset(t, 0, sizeof(t));
     26      }
     27      int sum(int x, int y){
     28          int cnt = 0, f = y;
     29          //int flag = x;
     30          while (x > 0){
     31                while (y > 0){
     32                      cnt += C[x][y];
     33                      y -= lowbit(y);
     34                }
     35                x -= lowbit(x);
     36                y = f;
     37          }
     38          return cnt;
     39      }
     40      void add(int x, int y){
     41           int f = y;
     42           while (x < SIZE){
     43                 while (y < SIZE){
     44                       C[x][y]++;
     45                       y += lowbit(y);
     46                 }
     47                 x += lowbit(x);
     48                 y = f;
     49           }
     50           return;
     51      }
     52      //二分搜索,查找x在k内相当的值 
     53      int search(int k, int x){
     54          int l = 0, r = 224, Ans;
     55          while (l <= r){
     56                int mid = (l + r) >> 1;
     57                if (t[k][mid] <= x) Ans = mid, l = mid + 1;
     58                else r = mid - 1;
     59          }
     60          return Ans;
     61      }
     62 }list[SIZE];
     63 struct DATA{
     64        int t[2];//影响m的树状数组的两个值,注意都要进行离散化 
     65        int x;//
     66 }rem[M]; 
     67 struct LSH{
     68        int num, order;
     69        bool operator < (LSH b)const{
     70             return num < b.num;//专门用来离散化 
     71        }
     72 }A[M];
     73 int data[N], c[3][N], n, m;
     74 int num[N];//num[N]代表i有i存在的逆序对的个数 
     75 ll tot;//记录逆序对的个数 
     76 
     77 ll sum(int k, int x){
     78     ll cnt = 0;
     79     while (x > 0){
     80           cnt += c[k][x];
     81           x -= lowbit(x);
     82     }
     83     return cnt;//记得要用ll 
     84 }
     85 void add(int k, int x){
     86      while (x <= n){
     87           c[k][x]++;
     88           x += lowbit(x);
     89      }
     90      return;
     91 }
     92 void init(){
     93      tot = 0;
     94      memset(num, 0, sizeof(num));
     95      memset(c, 0, sizeof(c));
     96      scanf("%d%d", &n, &m);
     97      for (int i = 1; i <= n; i++){
     98          int x;
     99          scanf("%d", &x);
    100          data[x] = i;
    101          int tmp = sum(0, x);
    102          num[x] += (i - 1 - tmp);//先求出在i之前的比i大的数
    103          num[x] += (x - tmp - 1);//后面比i小的数 
    104          tot += (i - 1 - tmp);
    105          add(0, x);
    106      }
    107      //printf("%d
    ", tot);
    108      //for (int i = 1; i <= n; i++) printf("%d
    ", num[i]);
    109 }
    110 //离散化 
    111 void prepare(){
    112      //a,b中两个值分别为位置和大小 
    113      for (int i = 1; i <= m; i++){
    114          int tmp;
    115          scanf("%d", &tmp);
    116          rem[i].t[0] = data[tmp];
    117          rem[i].t[1] = n - tmp + 1;
    118          rem[i].x = tmp;
    119      } 
    120      //for (int i = 1; i <= m; i++) printf("%d %d %d
    ", rem[i].t[0], rem[i].t[1], rem[i].x);
    121 }
    122 void get(int k, int l, int r, int x){
    123      int cnt = r - l + 1, pos = 1;
    124      for (int i = l; i <= r; i++){
    125          A[pos].order = i;
    126          A[pos].num = rem[i].t[k];
    127          pos++;
    128      }
    129      sort(A + 1, A + cnt + 1);
    130      for (int i = 1;i <= cnt; i++) list[x].t[k][i] = A[i].num;
    131      for (int i = 1;i <= cnt; i++) rem[A[i].order].t[k] = i;
    132 }
    133 void work(){
    134      for (int i = 0; i < SIZE; i++) list[i].init();
    135      int cnt = 0;//cnt是用来记录块的数量 
    136      for (int pos = 1; pos <= m; pos++){
    137          
    138          int l = pos;
    139          l = min(m , 224 + pos - 1);
    140          //从[l,m]这一段放在list[cnt]里面 
    141          get(0, pos, l, cnt);
    142          get(1, pos, l, cnt);
    143          for (int i = pos; i <= l; i++){
    144              printf("%lld
    ", tot);
    145              int tmp = list[cnt].sum(rem[i].t[0], rem[i].t[1]);
    146              for (int j = 0; j < cnt; j++) tmp += list[j].sum(list[j].search(0, list[cnt].t[0][rem[i].t[0]]), list[j].search(1, list[cnt].t[1][rem[i].t[1]]));
    147              
    148              tot -= (num[rem[i].x] - (tmp + (sum(2, rem[i].x) - (sum(1, list[cnt].t[0][rem[i].t[0]]) - tmp))));
    149              list[cnt].add(rem[i].t[0], rem[i].t[1]);
    150              add(1, list[cnt].t[0][rem[i].t[0]]);
    151              add(2, rem[i].x);
    152          }
    153          cnt++;
    154          pos = l;
    155      } 
    156 }
    157 
    158 int main(){
    159     #ifdef LOCAL
    160     freopen("data.txt",  "r",  stdin);
    161     freopen("out.txt",  "w",  stdout); 
    162     #endif
    163     init();
    164     prepare();
    165     if (m == 0) return 0;
    166     else work();
    167     return 0;
    168 }
    View Code
  • 相关阅读:
    python基础(常量,数据类型,if)
    c字符串操作函数
    磁盘读写,合并排序字符串
    5个学生,3门成绩,输入信息,保存到文件
    关于MQTT、HTTP、WebService
    循环队列Circular Queue
    ISR中断服务程序
    PID控制
    Linux定时器接口
    Embedded Agent
  • 原文地址:https://www.cnblogs.com/hoskey/p/4323465.html
Copyright © 2011-2022 走看看