P1393 动态逆序对

题目

P1393 动态逆序对

做题前写篇博客是个好方法

做法

题目规定仅有删除,给每个位置标个号,逆序对+时间轴,显然这是个三维偏序

很久没做过\(cdq\)了,就当模板题讲一下:

按删除的先后顺序为关键字排序分治,然后在\(cdq\)中按位置排序,同时前部分删除的时间<=后部分删除时间

此时前部分删除的一个点会影响到的贡献在后部分处理:1.位置大值小查询-值大数量;2.位置小值大查询-值小数量

My complete code

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=1e5;
inline LL Read(){
    LL x(0),f(1); char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1; c=getchar();
    }
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
LL n,m,ans;
LL tree[maxn],a[maxn],tmp[maxn],D[maxn],low[maxn];
inline LL Lowbit(LL x){
    return x&(-x);
}
inline void Add(LL x,LL val){
    for(;x<=n;x+=Lowbit(x))
        tree[x]+=val;
}
inline LL Query(LL x){
    LL ret(0);
    for(;x;x-=Lowbit(x))
        ret+=tree[x];
    return ret;
}
struct node{
    LL del,val,id,ans;
}q[maxn];
inline bool cmp1(node x,node y){
    return x.del<y.del;
}
inline bool cmp2(node x,node y){
    return x.id<y.id;
}
void Cdq(LL l,LL r){
    if(l==r)
        return;
    LL mid(l+r>>1);
    Cdq(l,mid),Cdq(mid+1,r);
    sort(q+l,q+mid+1,cmp2),sort(q+mid+1,q+r+1,cmp2);
    LL j=mid;
    for(LL i=l;i<=mid;++i){//big
        while(j<r&&q[j+1].id<q[i].id)
            Add(q[++j].val,1);
        q[i].ans+=Query(n)-Query(q[i].val);
    }
    for(LL i=mid+1;i<=j;++i)
        Add(q[i].val,-1);
    j=r+1;
    for(LL i=mid;i>=l;--i){
        while(j>mid+1&&q[j-1].id>q[i].id)
            Add(q[--j].val,1);
        q[i].ans+=Query(q[i].val-1);
    }
    for(LL i=j;i<=r;++i)
        Add(q[i].val,-1);
}
int main(){
    n=Read(),m=Read();
    for(LL i=1;i<=n;++i)
        tmp[i]=a[i]=Read();
    sort(tmp+1,tmp+1+n);
    for(LL i=1;i<=n;++i)
        a[i]=lower_bound(tmp+1,tmp+1+n,a[i])-tmp;
    for(LL i=n;i>=1;--i){
        ans+=Query(a[i]-1);
        Add(a[i],1);
    }

    for(LL i=1;i<=n;++i)
        q[i]=(node){n+1,a[i],i,0};
    for(LL i=1;i<=m;++i){
        D[i]=Read();
        q[D[i]].del=i;
    }
    memset(tree,0,sizeof(tree));
    sort(q+1,q+1+n,cmp1);
    Cdq(1,n);
    for(LL i=1;i<=n;++i)
        low[q[i].id]=q[i].ans;
    printf("%lld ",ans);
    for(LL i=1;i<=m;++i){
        ans-=low[D[i]];
        printf("%lld ",ans);
    }
    return 0;
}/*
6 3
5 4 2 6 3 1
2 1 4

11 7 4 2
*/

原文地址:https://www.cnblogs.com/y2823774827y/p/10279992.html

时间: 2024-11-01 15:24:07

P1393 动态逆序对的相关文章

bzoj3295动态逆序对

Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5362  Solved: 1814[Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数

[CQOI2011]动态逆序对

P1347 - [CQOI2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数. 以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个

bzoj3295【CQOI2011】动态逆序对

3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 3122  Solved: 986 [Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数

主席树初探 &amp; bzoj 3295: [Cqoi2011] 动态逆序对 题解

[原题] 3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 778  Solved: 263 [Submit][Status] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元

Bestcoder7(1004)hdu4988(经典问题:树状数组套treap求解动态逆序对)

Little Pony and Boast Busters Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 83    Accepted Submission(s): 32 Problem Description "I hereby challenge you, Ponyvillians: anything you can do

【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治

[BZOJ3295][Cqoi2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的

【BZOJ 3295】 [Cqoi2011]动态逆序对

3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1373  Solved: 465 [Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数

【Luogu1393】动态逆序对(CDQ分治)

[Luogu1393]动态逆序对(CDQ分治) 题面 题目描述 对于给定的一段正整数序列,我们定义它的逆序对的个数为序列中ai>aj且i < j的有序对(i,j)的个数.你需要计算出一个序列的逆序对组数及其删去其中的某个数的逆序对组数. 输入输出格式 输入格式: 第一行,两个数n,m,表示序列中有n个数,要删去m个数 第二行n个数,表示给定的序列. 第三行m个数,第i个数di表示要删去原序列中的第di个数. 输出格式: 一行m+1个数.第一个数表示给定序列的逆序对组数,第i+1个数表示删去第d

【算法】CDQ分治 -- 三维偏序 &amp; 动态逆序对

初次接触CDQ分治,感觉真的挺厉害的. 整体思路即分而治之,再用之前处理出来的答案统计之后的答案. 大概流程是: 对于区间 l ~ r : 1.处理 l ~mid, mid + 1 ~ r 的答案 2.分别排序规整 3.计算 l ~ mid 中每一个数对 mid + 1 ~ r 中的答案的贡献, 累加 4.得到区间l ~ r的答案 CDQ分治我一共也才做了两道题目, 就一起整理在这里了.大体都差不多,CDQ+树状数组分别维护两个维度. 1.三维偏序 #include <bits/stdc++.h