• 洛谷P1393 动态逆序对(CDQ分治)


    传送门

    题解

    听别人说这是洛谷用户的双倍经验啊……然而根本没有感觉到……因为另外的那题我是用树状数组套主席树做的……而且莫名其妙感觉那种方法思路更清晰(虽然码量稍稍大了那么一点点)……感谢Candy大佬教会了我CDQ的动态逆序对……莫名其妙1A了……

    因为是删除,所以可以看成倒着加入。而且没规定都在$n$以内,所以要离散。我们把每一个位置都表示成一个三元组$(t,x,y)$,其中$t$表示加入的时间,$x$表示在原数组中的位置,$y$表示离散之后的值。求逆序对,就代表求有多少个三元组满足$t'<t,x'<x,y'>y$或$t'<t,x'>x,y'<y$。我们可以先把时间这一维排序,然后CDQ的时候顺便排好$x$这一维,$y$这一维用树状数组求解。因为要找两种,所以CDQ的时候要两个分别找,这一部分的细节可以参考代码

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #define ll long long
     6 using namespace std;
     7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     8 char buf[1<<21],*p1=buf,*p2=buf;
     9 inline int read(){
    10     #define num ch-'0'
    11     char ch;bool flag=0;int res;
    12     while(!isdigit(ch=getc()))
    13     (ch=='-')&&(flag=true);
    14     for(res=num;isdigit(ch=getc());res=res*10+num);
    15     (flag)&&(res=-res);
    16     #undef num
    17     return res;
    18 }
    19 char sr[1<<21],z[20];int C=-1,Z;
    20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    21 inline void print(ll x){
    22     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    23     while(z[++Z]=x%10+48,x/=10);
    24     while(sr[++C]=z[Z],--Z);sr[++C]=' ';
    25 }
    26 const int N=4e4+5;
    27 int n,m,c[N],ty,yy[N];
    28 inline void add(int x,int val){
    29     for(;x<=ty;x+=x&-x) c[x]+=val;
    30 }
    31 inline int query(int x){
    32     int res=0;
    33     for(;x;x-=x&-x) res+=c[x];
    34     return res;
    35 }
    36 inline void clear(int x){
    37     for(;x<=ty;x+=x&-x)
    38     if(c[x]) c[x]=0;else break;
    39 }
    40 struct node{
    41     int t,x,y;
    42     node(){}
    43     node(int t,int x,int y):t(t),x(x),y(y){}
    44     bool operator <(const node &b)const
    45     {return x==b.x?y<b.y:x<b.x;}
    46 }a[N],p[N];
    47 inline bool cmptime(const node &a,const node &b){
    48     return a.t==b.t?a.x<b.x:a.t<b.t;
    49 }
    50 ll ans[N];
    51 void CDQ(int l,int r){
    52     if(l==r) return;
    53     int mid=l+r>>1;
    54     CDQ(l,mid),CDQ(mid+1,r);
    55     for(int i=l,j=l,k=mid+1;i<=r;){
    56         if(k>r||(j<=mid&&a[j]<a[k])) add(a[j].y,1),p[i++]=a[j++];
    57         else ans[a[k].t]+=query(n)-query(a[k].y),p[i++]=a[k++];
    58     }
    59     for(int i=l;i<=mid;++i) clear(a[i].y);
    60     for(int i=l;i<=r;++i) a[i]=p[i];
    61     for(int i=r;i>=l;--i){
    62         if(a[i].t<=mid) add(a[i].y,1);
    63         else ans[a[i].t]+=query(a[i].y-1);
    64     }
    65     for(int i=l;i<=r;++i) clear(a[i].y);
    66 }
    67 int main(){
    68     //freopen("testdata.in","r",stdin);
    69     n=read(),m=read();
    70     for(int i=1;i<=n;++i){
    71         yy[i]=read(),a[i]=node(0,i,yy[i]);
    72     }
    73     sort(yy+1,yy+1+n);
    74     ty=unique(yy+1,yy+1+n)-yy-1;
    75     for(int i=1;i<=n;++i) a[i].y=lower_bound(yy+1,yy+1+ty,a[i].y)-yy;
    76     int Time=n;
    77     for(int i=1;i<=m;++i){
    78         int k=read();a[k].t=Time--;
    79     }
    80     for(int i=1;i<=n;++i) if(!a[i].t) a[i].t=Time--;
    81     sort(a+1,a+1+n,cmptime);
    82     CDQ(1,n);
    83     for(int i=1;i<=n;++i) ans[i]+=ans[i-1];
    84     for(int i=n;i>=n-m;--i) print(ans[i]);
    85     Ot();
    86     return 0;
    87 }
  • 相关阅读:
    java工程师要求
    系统架构设计师知识模块
    Mybatis使用训练
    项目—视频直播系统
    [数算]概率
    查看镜像文件
    Hadoop启动命令
    Hadoop启动命令
    HDFS设置配额管理
    HDFS设置配额管理
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9461956.html
Copyright © 2020-2023  润新知