zoukankan      html  css  js  c++  java
  • 【CQOI2011】动态逆序对 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

    思路

        最近一直都在做一些树套树的题目呢=。=

        求解逆序对有两种方法,树状数组和归并排序,前者一般来说优于后者。。而且好写太多了。

        首先算出最初的答案ans,和一个数的左边比它大的数以及右边比它小的数的个数。

        每次删除一个数之后,ans就减去左边比他大以及右边比他小的数的个数。

        然而前面删除的时候有可能会对后面产生影响,于是我们维护在[l,r]范围内被删除的比I小的数的个数,那么就用树状数组套线段树组成。

        外层树状数组记录权值,内层线段树记录位置,为了节省空间,线段树动态开点(要不然二维树状数组不就好了么。。)

        一开始我没有记录最开始一个数的左边比它大的数以及右边比它小的数的个数,而是动态维护,导致线段树疯狂开点,怒E。。

        一次查询最多只会涉及到Log2n个节点(树状数组Logn次查询*每次查询Logn个节点),于是总共的空间是mLog2n的,完全可以接受。

        如果直接动态维护一个数的左边比它大的数以及右边比它小的数的个数的话空间复杂度是O(n2)的,Terrible。。

      

      1 #include <iostream>
      2 #include <cstring>
      3 #include <string>
      4 #include <cstdio>
      5 #include <cstdlib>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <queue>
      9 #include <stack>
     10 #include <map>
     11 #include <set>
     12 #include <list>
     13 #include <vector>
     14 #include <ctime>
     15 #include <functional>
     16 #define pritnf printf
     17 #define scafn scanf
     18 #define sacnf scanf
     19 #define For(i,j,k) for(int i=(j);i<=(k);(i)++)
     20 #define Clear(a) memset(a,0,sizeof(a))
     21 using namespace std;
     22 typedef unsigned int Uint;
     23 const int INF=0x3fffffff;
     24 ///==============struct declaration==============
     25 struct Seg_Node{
     26    Seg_Node *lc,*rc;
     27    int addv;
     28    long long sum;
     29    Seg_Node (){lc=rc=NULL;sum=0;addv=0;}
     30 };
     31 ///==============var declaration=================
     32 const int MAXN=100050;
     33 int n,L,R,k,v,m;
     34 long long ans=0;
     35 Seg_Node *BitTree[MAXN];
     36 int A[MAXN],Index[MAXN],Prefix[MAXN];
     37 int LeftGreater[MAXN],RightLess[MAXN],Bit[MAXN];
     38 ///==============function declaration============
     39 void Add_Bit(int x);
     40 void Add_Prefix(int x,int val);
     41 int lowbit(int x){return x&-x;}
     42 int Query_Prefix(int x);
     43 long long Query_Bit(int x);
     44 void Add_Seg(Seg_Node *&Node,int l,int r);
     45 long long Query_Seg(Seg_Node *&Node,int l,int r,int add);
     46 void update(Seg_Node *&Node,int l,int r);
     47 inline void qread(int &x);
     48 void Add_Bit(int *P,int x);
     49 int Query_Bit(int *P,int x);
     50 ///==============main code=======================
     51 int main()
     52 {
     53 //#define FILE__
     54 #ifdef FILE__
     55    freopen("input.txt","r",stdin);
     56    freopen("output.txt","w",stdout);
     57 #endif
     58    scanf("%d%d",&n,&m);
     59    for(int i=1;i<=n;i++){
     60       qread(A[i]);
     61       Index[A[i]]=i;k=i;v=1;
     62       Add_Prefix(i,1);Add_Bit(Bit,A[i]);
     63       LeftGreater[i]=i-Query_Bit(Bit,A[i]);
     64       ans+=LeftGreater[i];
     65    }
     66    memset(Bit,0,sizeof(Bit));
     67    for(int i=n;i>=1;i--){
     68       Add_Bit(Bit,A[i]);
     69       RightLess[i]=Query_Bit(Bit,A[i]-1);
     70    }
     71    while (m--){
     72       int num,pos;qread(num);pos=Index[num];
     73       printf("%lld
    ",ans);
     74       int Left=0,Right=0;
     75       ans-=LeftGreater[pos]+RightLess[pos];
     76       L=1,R=pos-1;
     77       if (L<=R)
     78          Left=Query_Bit(n)-Query_Bit(num);
     79       L=pos+1,R=n;
     80       if (L<=R)
     81          Right=Query_Bit(num);
     82       Add_Prefix(pos,-1);k=pos;v=1;
     83       Add_Bit(num);
     84       ans+=Left+Right;
     85    }
     86    return 0;
     87 }
     88 ///================fuction code====================
     89 void Add_Bit(int x){
     90    while (x<=n){
     91       Add_Seg(BitTree[x],1,n);
     92       x+=lowbit(x);
     93    }
     94 }
     95 void Add_Prefix(int x,int val){
     96    while (x<=n){
     97       Prefix[x]+=val;
     98       x+=lowbit(x);
     99    }
    100 }
    101 int Query_Prefix(int x){
    102    int res=0;
    103    while (x>0){
    104       res+=Prefix[x];
    105       x-=lowbit(x);
    106    }
    107    return res;
    108 }
    109 long long Query_Bit(int x){
    110    long long res=0;
    111    while (x>0){
    112       res+=Query_Seg(BitTree[x],1,n,0);
    113       x-=lowbit(x);
    114    }
    115    return res;
    116 }
    117 void Add_Seg(Seg_Node *&Node,int l,int r){
    118    if (Node==NULL)   Node=new(Seg_Node);
    119    int m=(l+r)>>1;
    120    if (l==r){
    121       Node->addv+=v;
    122       Node->sum+=v;
    123       return ;
    124    }
    125    if (m>=k)   Add_Seg(Node->lc,l,m);
    126    else  Add_Seg(Node->rc,m+1,r);
    127    update(Node,l,r);
    128 }
    129 void update(Seg_Node *&Node,int l,int r){
    130    Node->sum=0;
    131    if (Node->lc!=NULL) Node->sum+=Node->lc->sum;
    132    if (Node->rc!=NULL) Node->sum+=Node->rc->sum;
    133    Node->sum+=(r-l+1)*Node->addv;
    134 }
    135 long long Query_Seg(Seg_Node *&Node,int l,int r,int add){
    136    if (Node==NULL)   return (r-l+1)*add;
    137    if (L<=l&&r<=R)   return Node->sum+add*(r-l+1);
    138    int m=(l+r)>>1;
    139    long long Left=0,Right=0;
    140    if (m>=L) Left=Query_Seg(Node->lc,l,m,add+Node->addv);
    141    if (m<R) Right=Query_Seg(Node->rc,m+1,r,add+Node->addv);
    142    return Left+Right;
    143 }
    144 inline void qread(int &x){
    145     char cha;
    146     while(cha=getchar()) if(isdigit(cha)) break;
    147     x=cha-'0';
    148     while(cha=getchar()){
    149         if(!isdigit(cha)) break;
    150         x=10*x+cha-'0';
    151     }
    152 }
    153 void Add_Bit(int *P,int x){
    154    while (x<=n){
    155       P[x]++;
    156       x+=lowbit(x);
    157    }
    158 }
    159 int Query_Bit(int *P,int x){
    160    int res=0;
    161    while (x>0){
    162       res+=P[x];
    163       x-=lowbit(x);
    164    }
    165    return res;
    166 }
    BZOJ3295
  • 相关阅读:
    【请教】在vim中如何快速选中一个单词?并且让文本中的所有这个
    SQL中为了加强分类表的记录有效性,把主键和外键设计在了同一张表内
    JS不忘本之switch篇~建立一个菜单,并为菜单的参数来设置它的具体操作
    JS不忘本之JS类篇~类,方法,属性,子类,扩展方法在JS里的实现
    移入页面上空文本框时,让它变为焦点,移出清除焦点
    EF中数据优先,模型优先和代码优先
    关于ApplicationContext的初始化
    Linux下无线路由器的软件开发
    as3实现的拼图游戏
    AppWidgets
  • 原文地址:https://www.cnblogs.com/Houjikan/p/4342632.html
Copyright © 2011-2022 走看看