zoukankan      html  css  js  c++  java
  • bzoj3295 [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

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

    HINT

    N<=100000 M<=50000

    正解:CDQ分治或树状数组套主席树。

    这题用来考试,一堆50分暴力,一人写出正解但是没开long long。。

    考虑把删除变成插入,那么每次插入是按照时间排序的。那么只要满足i<j,ai>aj,ti<tj,那么这就是一个逆序对。于是这题就变成裸的三维偏序了。

    还有一种做法:使用带修改的主席树。每次删除就是直接删除,查询就查出当前数前面比它大的数和当前树后面比它小的数。注意空间优化。


    CDQ分治:

     1 //It is made by wfj_2048~
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <cstdlib>
     6 #include <cstdio>
     7 #include <vector>
     8 #include <cmath>
     9 #include <queue>
    10 #include <stack>
    11 #include <map>
    12 #include <set>
    13 #define inf (1<<30)
    14 #define il inline
    15 #define RG register
    16 #define ll long long
    17 #define lb(x) (x & -x)
    18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    19 
    20 using namespace std;
    21 
    22 struct node{ int x,y,t; }q[100010],qu[100010];
    23 
    24 ll c[100010],ans[100010],Ans;
    25 int match[100010],n,m;
    26 
    27 il int gi(){
    28     RG int x=0,q=0; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    29     if (ch=='-') q=1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q ? -x : x;
    30 }
    31 
    32 il int cmp(const node &a,const node &b){ return a.x<b.x || (a.x==b.x && a.y<b.y) || (a.x==b.x && a.y==b.y && a.t<b.t); }
    33 
    34 il void add(RG int x,RG int v){ for (RG int i=x;i<=n;i+=lb(i)) c[i]+=(ll)v; return; }
    35 
    36 il ll query(RG int x){ RG ll res=0; for (RG int i=x;i;i-=lb(i)) res+=c[i]; return res; }
    37 
    38 il void solve(RG int l,RG int r){
    39     if (l>=r) return; RG int mid=(l+r)>>1,t1=l-1,t2=mid;
    40     for (RG int i=l;i<=r;++i) if (q[i].t<=mid) add(q[i].y,1); else ans[q[i].t]+=query(n)-query(q[i].y);
    41     for (RG int i=l;i<=r;++i) if (q[i].t<=mid) add(q[i].y,-1);
    42     for (RG int i=r;i>=l;--i) if (q[i].t<=mid) add(q[i].y,1); else ans[q[i].t]+=query(q[i].y);
    43     for (RG int i=r;i>=l;--i) if (q[i].t<=mid) add(q[i].y,-1);
    44     for (RG int i=l;i<=r;++i) if (q[i].t<=mid) qu[++t1]=q[i]; else qu[++t2]=q[i];
    45     for (RG int i=l;i<=r;++i) q[i]=qu[i]; solve(l,mid),solve(mid+1,r); return;
    46 }
    47 
    48 il void work(){
    49     n=gi(),m=gi(); for (RG int i=1;i<=n;++i) q[i].x=i,q[i].y=gi(),match[q[i].y]=i; RG int ti=n,v;
    50     for (RG int i=1;i<=m;++i) v=gi(),q[match[v]].t=ti--; for (RG int i=1;i<=n;++i) if (!q[i].t) q[i].t=ti--;
    51     sort(q+1,q+n+1,cmp); solve(1,n); for (RG int i=1;i<=n;++i) Ans+=ans[i];
    52     for (RG int i=n;i>n-m;--i){ printf("%lld
    ",Ans); Ans-=ans[i]; } return;
    53 }
    54 
    55 int main(){
    56     File("dynamic");
    57     work();
    58     return 0;
    59 }

    树状数组+主席树:

     1 //It is made by wfj_2048~
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <complex>
     5 #include <cstring>
     6 #include <cstdlib>
     7 #include <cstdio>
     8 #include <vector>
     9 #include <cmath>
    10 #include <queue>
    11 #include <stack>
    12 #include <map>
    13 #include <set>
    14 #define N (100010)
    15 #define il inline
    16 #define RG register
    17 #define ll long long
    18 #define lb(x) (x & -x)
    19 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    20 
    21 using namespace std;
    22 
    23 int sum[200*N],ls[200*N],rs[200*N],rt[N],a[N],vis[N],n,m,sz;
    24 ll ans;
    25 
    26 il int gi(){
    27     RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    28     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
    29 }
    30 
    31 il void update(RG int x,RG int &y,RG int l,RG int r,RG int v,RG int fg){
    32     if (!y) y=++sz; //节省空间!!!
    33     sum[y]=sum[x]+fg,ls[y]=ls[x],rs[y]=rs[x];
    34     if (l==r) return; RG int mid=(l+r)>>1;
    35     v<=mid ? update(ls[x],ls[y],l,mid,v,fg) : update(rs[x],rs[y],mid+1,r,v,fg);
    36 }
    37 
    38 il int query1(RG int x,RG int l,RG int r,RG int v){
    39     if (l==r) return 0; RG int mid=(l+r)>>1;
    40     return v<=mid ? query1(ls[x],l,mid,v)+sum[rs[x]] : query1(rs[x],mid+1,r,v);
    41 }
    42 
    43 il int query2(RG int x,RG int l,RG int r,RG int v){
    44     if (l==r) return 0; RG int mid=(l+r)>>1;
    45     return v<=mid ? query2(ls[x],l,mid,v) : query2(rs[x],mid+1,r,v)+sum[ls[x]];
    46 }
    47 
    48 il void work(){
    49     n=gi(),m=gi();
    50     for (RG int i=1;i<=n;++i){
    51     a[i]=gi(),vis[a[i]]=i;
    52     for (RG int x=i;x<=n;x+=lb(x)) update(rt[x],rt[x],1,n,a[i],1);
    53     }
    54     for (RG int i=2;i<=n;++i)
    55     for (RG int x=i-1;x;x-=lb(x)) ans+=query1(rt[x],1,n,a[i]);
    56     for (RG int i=1;i<=m;++i){
    57     printf("%lld
    ",ans); RG int k=vis[gi()];
    58     for (RG int x=k-1;x;x-=lb(x)) ans-=query1(rt[x],1,n,a[k]);
    59     for (RG int x=k;x;x-=lb(x)) ans+=query2(rt[x],1,n,a[k]);
    60     for (RG int x=n;x;x-=lb(x)) ans-=query2(rt[x],1,n,a[k]);
    61     for (RG int x=k;x<=n;x+=lb(x)) update(rt[x],rt[x],1,n,a[k],-1);
    62     }
    63     return;
    64 }
    65 
    66 int main(){
    67     File("dynamic");
    68     work();
    69     return 0;
    70 }
  • 相关阅读:
    171-滑动窗口问题
    170-133. 克隆图
    169-150. 逆波兰表达式求值
    windows相对路径设置与取消小工具[提效]
    Sword 38
    Sword 33
    Sword 28
    Sword 26
    Sword 12
    Sword 07
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6416589.html
Copyright © 2011-2022 走看看