题目描述

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

输入输出格式

输入格式:

输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。

输出格式:

输出包含m行,依次为删除每个元素之前,逆序对的个数。

题解

我们发现一个数的贡献,就是就是t'<t(删除时间),xb'<xb(下标),w'>w(权值)的数的数量和t'>t,xb'>xb,w'<w的数的数量之和。

这就是一个三维偏序类型的题,所以做两遍CDQ分治分别的到这两种贡献。最后用总逆序对数减去就好了。

1A真开心。。。

 #include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
const long long N=;
long long n,m,a[N],b[N],tmp,tr[N],ans[N],book[N],ma[N],tot;
struct query{
long long id,xb,w;
}q[N],c[N];
bool cmp(query a,query b){
return a.id>b.id;
}
void gb(long long l,long long r){
if(l==r)return;
long long mid=(l+r)>>;
gb(l,mid);
gb(mid+,r);
long long ll=l;
long long lr=mid+;
long long cnt=;
while(ll<=mid&&lr<=r){
cnt++;
if(a[ll]<a[lr]){
b[cnt]=a[ll++];
}
else{
b[cnt]=a[lr++];
tmp+=mid-ll+;
}
}
while(ll<=mid)b[++cnt]=a[ll++];
while(lr<=r)b[++cnt]=a[lr++];
for(long long i=l;i<=r;i++){
a[i]=b[i-l+];
}
}
long long lowbit(long long x){
return x&-x;
}
void add(long long x,long long w){
for(long long i=x;i<=n;i+=lowbit(i)){
tr[i]+=w;
}
}
long long getsum(long long x){
long long ans=;
for(long long i=x;i>=;i-=lowbit(i)){
ans+=tr[i];
}
return ans;
}
void cdq(long long l,long long r){
if(l==r)return;
long long mid=(l+r)>>;
cdq(l,mid);cdq(mid+,r);
long long ll=l;long long rl=mid+;long long now=;
while(ll<=mid&&rl<=r){
if(q[ll].xb<q[rl].xb){
add(q[ll].w,);
c[++now]=q[ll++];
}
else{
ans[q[rl].id]+=getsum(n)-getsum(q[rl].w);
c[++now]=q[rl++];
}
}
while(ll<=mid){
add(q[ll].w,);
c[++now]=q[ll++];
}
while(rl<=r){
ans[q[rl].id]+=getsum(n)-getsum(q[rl].w);
c[++now]=q[rl++];
}
for(long long i=l;i<=mid;i++)add(q[i].w,-);
for(long long i=l;i<=r;i++)q[i]=c[i-l+];
}
void CDQ(long long l,long long r){
if(l==r)return;
long long mid=(l+r)>>;
CDQ(l,mid);CDQ(mid+,r);
long long ll=l;long long rl=mid+;long long now=;
while(ll<=mid&&rl<=r){
if(q[ll].xb>q[rl].xb){
add(q[ll].w,);
c[++now]=q[ll++];
}
else{
ans[q[rl].id]+=getsum(q[rl].w);
c[++now]=q[rl++];
}
}
while(ll<=mid){
add(q[ll].w,);
c[++now]=q[ll++];
}
while(rl<=r){
ans[q[rl].id]+=getsum(q[rl].w);
c[++now]=q[rl++];
}
for(long long i=l;i<=mid;i++)add(q[i].w,-);
for(long long i=l;i<=r;i++)q[i]=c[i-l+];
}
int main(){
scanf("%lld%lld",&n,&m);
for(long long i=;i<=n;i++){
scanf("%lld",&a[i]);
ma[a[i]]=i;
}
for(long long i=;i<=m;i++){
long long x;
scanf("%lld",&x);
q[i].id=i;q[i].xb=ma[x];q[i].w=x;
book[ma[x]]=;
}
tot=m;
for(long long i=;i<=n;i++){
if(book[i]==){
q[++tot].id=m+;q[tot].xb=i;q[tot].w=a[i];
}
}
sort(q+,q+n+,cmp);
cdq(,n);
sort(q+,q+n+,cmp);
CDQ(,n);
gb(,n);
for(long long i=;i<=m;i++){
printf("%lld\n",tmp);
tmp-=ans[i];
}
return ;
}

luogu P3157 [CQOI2011]动态逆序对(CDQ分治)的更多相关文章

  1. LUOGU P3157 [CQOI2011]动态逆序对(CDQ 分治)

    传送门 解题思路 cdq分治,将位置看做一维,修改时间看做一维,权值看做一维,然后就转化成了三维偏序,用排序+cdq+树状数组.注意算删除贡献时要做两次cdq,分别算对前面和后面的贡献. #inclu ...

  2. 洛谷 P3157 [CQOI2011]动态逆序对 | CDQ分治

    题目:https://www.luogu.org/problemnew/show/3157 题解: 1.对于静态的逆序对可以用树状数组做 2.我们为了方便可以把删除当成增加,可以化动为静 3.找到三维 ...

  3. P3157 [CQOI2011]动态逆序对 CDQ分治

    一道CDQ分治模板题简单来说,这道题是三维数点对于离线的二维数点,我们再熟悉不过:利用坐标的单调递增性,先按更坐标排序,再按纵坐标排序更新和查询时都直接调用纵坐标.实际上,我们是通过排序将二维中的一维 ...

  4. P3157 [CQOI2011]动态逆序对 (CDQ解决三维偏序问题)

    P3157 [CQOI2011]动态逆序对 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任 ...

  5. [BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j,且 ...

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

    [BZOJ3295][Cqoi2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依 ...

  7. bzoj3295: [Cqoi2011]动态逆序对(cdq分治+树状数组)

    3295: [Cqoi2011]动态逆序对 题目:传送门 题解: 刚学完cdq分治,想起来之前有一道是树套树的题目可以用cdq分治来做...尝试一波 还是太弱了...想到了要做两次cdq...然后伏地 ...

  8. BZOJ3295 [Cqoi2011]动态逆序对 —— CDQ分治

    题目链接:https://vjudge.net/problem/HYSBZ-3295 3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 1 ...

  9. [Luogu P3157][CQOI2011]动态逆序对 (树套树)

    题面 传送门:[CQOI2011]动态逆序对 Solution 一开始我看到pty巨神写这套题的时候,第一眼还以为是个SB题:这不直接开倒车线段树统计就完成了吗? 然后冷静思考了一分钟,猛然发现单纯的 ...

随机推荐

  1. svn创建分支的做法

    作者:朱金灿 来源:http://blog.csdn.net/clever101 1.  首先选择你要创建分支的工作目录,如下图: 2.选择要创建分支的路径.注释以及版本,选择HEADrevision ...

  2. 【算法】Dijkstra算法(单源最短路径问题)(路径还原) 邻接矩阵和邻接表实现

    Dijkstra算法可使用的前提:不存在负圈. 负圈:负圈又称负环,就是说一个全部由负权的边组成的环,这样的话不存在最短路,因为每在环中转一圈路径总长就会边小. 算法描述: 1.找到最短距离已确定的顶 ...

  3. Java中如何解决线程安全问题

    给出一个问题,如下: 解决方案如下: public class Demo_5 { public static void main(String[] args) { //创建一个窗口 TicketWin ...

  4. php截取字符串|php截取字符串前几位|php截取中文字符串

    转 截取字符串专题:php截取字符串函数,php 字符串长度,php截取字符串前几位 PHP截取中文字符串(mb_substr)和获取中文 => http://www.q3060.com/lis ...

  5. Msql免安装版安装

     文首提要:             我下载的MySQL版本是:mysql-5.7.17-winx64.zip  Archive版:系统:Windows7 64位. 一.解压文件 下载好MySQL后, ...

  6. Java Class文件结构

    此文件格式为JAVA7的格式,可能与JAVA6 CLASS不一致. 每一个Class都对应着唯一的一个类或借口的定义信息.这里,我们称为"Class文件格式"只是通俗的将任意一个符 ...

  7. redhat 7 cenos 7 网络配置文件

    Cenos 7 TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no DEFROUTE=yes IPV4_FAILURE_FATAL=no NAME=eth0 ...

  8. MySQL 数据还原

    1.1还原使用mysqldump命令备份的数据库的语法如下: mysql -u root -p [dbname] < backup.sq 示例: mysql -u root -p < C: ...

  9. Qt之QThread

    简述 QThread类提供了与系统无关的线程. QThread代表在程序中一个单独的线程控制.线程在run()中开始执行,默认情况下,run()通过调用exec()启动事件循环并在线程里运行一个Qt的 ...

  10. HDU 5274(LCA + 线段树)

    Dylans loves tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...