• bzoj 3295 [Cqoi2011]动态逆序对(cdq分治,BIT)


    【题目链接】

       

       http://www.lydsy.com/JudgeOnline/problem.php?id=3295

    【题意】

       

        n个元素依次删除m个元素,求删除元素之前序列有多少个逆序对。

    【思路】

        cdq分治

        这个题转化一下可以变成刚刚做过的三维偏序。

        首先有两个量:序 和 值,可以将样例写成
        x   1 2 3 4 5

        y   1 5 3 4 2

        然后因为我们要删除一些东西,所以加上时间,则样例变为

        t   1 2 3 4 5

        x   3 5 4 1 2

        y   3 2 4 1 5

        删除顺序就是按照t从大到小。我们把它看作t从小到大的插入结点。

        则我们要求的是,一个结点在t时刻插入,左边有多少个比它大,右边有多少个比它小,设这个点为(t0,x0,y0),则我们要求的就是满足

        t<t0,x<x0,y>y0

        t<t0,x>x0,y<y0

        的点数。因为具体的值对结果并无影响我们可以通过把a改成n-a+1来改变符号的方向,具体就是求满足

        t<t0,x<x0,y<(n-y0+1)

        t<t0,x<(n-x0+1),y<y0

        的点数。

      于是问题变成了刚做过的 陌上花开 问题。

      最后统计每个时间点发生之前产生的所有逆序对。   

    【代码】

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #define rep(a,b,c) for(int a=b;a<=c;++a)
     5 using namespace std;
     6 
     7 typedef long long ll;
     8 const int N =3*1e5+10;
     9 
    10 void read(int &x) {
    11     char c=getchar(); x=0;
    12     while(!isdigit(c)) c=getchar();
    13     while(isdigit(c)) x=x*10+c-'0',c=getchar();
    14 }
    15 
    16 struct Node {
    17     int a,b,c,ans;
    18     bool operator<(const Node& rhs) const {
    19         return a<rhs.a;
    20     }
    21 }q[N],T[N];
    22 bool cmp(const Node& x,const Node& y)
    23 {
    24     return x.b<y.b||(x.b==y.b&&x.c>y.c);
    25 }
    26 
    27 int n,m,mx,C[N],rk[N];
    28 ll ans[N];
    29 
    30 void add(int x,int v)
    31 {
    32     for(;x<=mx;x+=x&-x) C[x]+=v;
    33 }
    34 int query(int x)
    35 {
    36     int res=0;
    37     for(;x;x-=x&-x) res+=C[x];
    38     return res;
    39 }
    40 
    41 void solve(int l,int r)
    42 {
    43     if(l==r) return ;
    44     int mid=(l+r)>>1;
    45     solve(l,mid) , solve(mid+1,r);
    46     int l1=l,l2=mid+1,i;
    47     while(l2<=r) {
    48         while(l1<=mid&&q[l1].b<q[l2].b) {
    49             add(q[l1].c,1);
    50             l1++;
    51         }
    52         q[l2].ans+=query(q[l2].c);
    53         l2++;
    54     }
    55     for(i=l;i<l1;i++) add(q[i].c,-1);
    56     l1=l,l2=mid+1; int now=l;
    57     while(l1<=mid||l2<=r) {
    58         if(l2>r||l1<=mid&&cmp(q[l1],q[l2])) T[now++]=q[l1++];
    59         else T[now++]=q[l2++];
    60     }
    61     for(int i=l;i<=r;i++) q[i]=T[i];
    62 }
    63 
    64 int main()
    65 {
    66     read(n),read(m); mx=n+5;
    67     rep(i,1,n) { q[i].b=i; read(q[i].c); }
    68     int a;
    69     rep(i,1,m) { read(a); rk[a]=i; }
    70     int sz=m;
    71     rep(i,1,n) if(!rk[i]) rk[i]=++sz;
    72     rep(i,1,n) q[i].a=n-rk[q[i].c]+1;
    73     sort(q+1,q+n+1);
    74     rep(i,1,n) q[i].b=n-q[i].b+1;
    75     solve(1,n);
    76     sort(q+1,q+n+1);
    77     rep(i,1,n) {
    78         q[i].b=n-q[i].b+1;
    79         q[i].c=n-q[i].c+1;
    80     }
    81     solve(1,n);
    82     rep(i,1,n) ans[q[i].a]=q[i].ans;
    83     rep(i,1,n) ans[i]+=ans[i-1];
    84     for(int i=n;i>n-m;i--)
    85         printf("%lld
    ",ans[i]);
    86     return 0;
    87 }
  • 相关阅读:
    C/C++网络编程2——socket函数
    C/C++网络编程1——linux下实现
    nginx_2_nginx进程模型
    nginx_1_初始nginx
    C++11并发编程4------线程间共享数据
    C++11并发编程3------线程传参
    C++11并发编程2------线程管理
    C++11并发编程1------并发介绍
    打造自己的开发环境
    gcc/g++/make/cmake/makefile/cmakelists的恩恩怨怨
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5255440.html
Copyright © 2020-2023  润新知