zoukankan      html  css  js  c++  java
  • BZOJ3295 [CQOI2011]动态逆序对

    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

    正解:cdq分治或带修改主席树

    解题报告:为了好好练练主席树,强行把这道cdq水题用带修改主席树做一遍

    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <string>
    #include <cstring>
    #include <algorithm>
    #define RG register
    #define ll long long
    const int N = 10000000;
    const int M = 200005;
    
    using namespace std;
    
    int gi(){
        RG char ch=getchar();RG int x=0;
        while(ch<'0' || ch>'9') ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    
    struct dota{
        int l,r;
        int s;
    }tr[N];
    
    int rt[M],f[M],L[M],g[M],ra[M];
    ll v[M],ans;
    int n,m,cnt;
    bool vis[M];
    
    void build(int &x,int s,int l,int r){
        if (x==0) x=++cnt;
        ++tr[x].s;
        if (l==r) return;
        int mid=(l+r)>>1;
        if (s<=mid) build(tr[x].l,s,l,mid);
        else build(tr[x].r,s,mid+1,r);
        return;
    }
    
    void work(int x,int s){
        while(x<n){
            build(rt[x],s,1,n);
            x+=x&(-x);
        }
        return;
    }
    
    int check(int x,int l,int r,int ql,int qr){
        if (ql<=l && r<=qr) return tr[x].s;
        int mid=(l+r)>>1,ans=0;
        if (ql<=mid) ans+=check(tr[x].l,l,mid,ql,qr);
        if (qr>mid)  ans+=check(tr[x].r,mid+1,r,ql,qr);
        return ans;
    }
    
    ll query(int x,int l,int r){
        int k=0;ll s=0;
        while(x){
            L[++k]=rt[x];
            x-=x&(-x);
        }
        for (RG int i=1; i<=k; ++i)
            s+=check(L[i],1,n,l,r);
        return s;
    }
    
    int main(){
        n=gi()+1,m=gi();
        for (RG int i=1; i<n; ++i) f[i]=gi(),ra[f[i]]=i;
        for (RG int i=1; i<=m; ++i) g[i]=gi(),vis[g[i]]=1;
        for (RG int i=1; i<n; ++i) if (vis[f[i]]==0){
                ans+=query(i,f[i]+1,n);
                ans+=query(n-1,1,f[i]);
                ans-=query(i,1,f[i]);
                work(i,f[i]);
            }
        for (RG int i=m; i>=1; --i){
            int w=ra[g[i]];
            work(w,g[i]);
            ans+=query(w,g[i]+1,n);
            ans+=query(n-1,1,g[i]);
            ans-=query(w,1,g[i]);
            v[i]=ans;
        }
        for (RG int i=1; i<=m; ++i) printf("%lld
    ",v[i]);
        return 0;
    }
  • 相关阅读:
    转 [Lucene.Net] 基本用法
    万商网与Alibaba等的比较
    B2B闯入者 新势力正在崛起
    项目管理随想一
    【转载】/proc目录中的重要信息
    文件名乱码转换器
    C函数调用中对入参取地址引发的问题
    编译通过的代码不算什么,一眼能看懂的代码才算好代码
    Handler使用
    删除system/app下的apk
  • 原文地址:https://www.cnblogs.com/cjk2001/p/6482833.html
Copyright © 2011-2022 走看看