zoukankan      html  css  js  c++  java
  • bzoj 3295 动态逆序对 (三维偏序,CDQ+树状数组)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3295

    思路:

    可以将这道题看成倒着插入,这样就可以转化成求逆序对数,用CDQ分治降维,正反用树状数组求两遍逆序对就好了。

    这道题还可以用在线的树套树或者可持久化线段树来写。。

    实现代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int M = 2e5+10;
    struct node{
         int t,x,y;
         int kind,id;
         node() {}
         node(int a,int b,int c,int d,int e = 0):t(a),x(b),y(c),kind(d),id(e){}
         bool operator < (const node &k) const {
             if(x == k.x) return y<k.y;
             return x < k.x;
         }
    };
    int n,m,a[M],pos[M],x,c[M],tim,len;
    node q[M],t[M];
    ll ans[M];
    void add(int x,int val){
         while(x <= n){
             c[x] += val;
             x += (x&-x);
         }
    }
    
    int getsum(int x){
        int sum = 0;
        while(x){
            sum += c[x];
            x -= (x&-x);
        }
        return sum;
    }
    
    void cdq(int l,int r){
        if(l == r) return ;
        int mid = (l + r) >> 1;
        for(int i = l;i <= r;i ++){
            if(q[i].t <= mid) add(q[i].y,q[i].kind);
            else ans[q[i].id] += q[i].kind*(getsum(n) - getsum(q[i].y));
        }
        for(int i = l;i <= r;i ++)
            if(q[i].t <= mid) add(q[i].y,-q[i].kind);
    
        for(int i = r;i >= l;i --){
            if(q[i].t <= mid) add(q[i].y,q[i].kind);
            else ans[q[i].id] += q[i].kind*getsum(q[i].y-1);
        }
        for(int i = l;i <= r;i ++)
            if(q[i].t <= mid) add(q[i].y,-q[i].kind);
    
        int L = l,R = mid+1;
        for(int i = l;i <= r;i ++){
            if(q[i].t <= mid) t[L++] = q[i];
            else t[R++] = q[i];
        }
        for(int i = l;i <= r;i ++) q[i] = t[i];
        cdq(l,mid); cdq(mid+1,r);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= n;i ++){
            scanf("%d",&a[i]);
            pos[a[i]] = i; q[++len] = node(++tim,i,a[i],1,0);
        }
        for(int i = 1;i <= m;i ++){
            scanf("%d",&x);
            q[++len] = node(++tim,pos[x],x,-1,i);
        }
        sort(q+1,q+1+len);
        cdq(1,len);
        for(int i = 1;i <= m;i ++){
            ans[i] += ans[i-1];
            printf("%lld
    ",ans[i-1]);
        }
        return 0;
    }
  • 相关阅读:
    杂想
    验证码再次学习。(处理方法汇总)
    神经网络学习入门 -01
    基于本地文字提取的有效的定位和识别场景文字
    C#学习总结~~~
    Deep Learning!!!
    记事本也能批量更名
    家庭一台电脑多人上网方法
    基于 OS X Mavericks 系统
    关于中文编程是解决中国程序员效率的秘密武器的问题思考
  • 原文地址:https://www.cnblogs.com/kls123/p/9523242.html
Copyright © 2011-2022 走看看