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

思路

最近一直都在做一些树套树的题目呢=。=

求解逆序对有两种方法,树状数组和归并排序,前者一般来说优于后者。。而且好写太多了。

首先算出最初的答案ans,和一个数的左边比它大的数以及右边比它小的数的个数。

每次删除一个数之后,ans就减去左边比他大以及右边比他小的数的个数。

然而前面删除的时候有可能会对后面产生影响,于是我们维护在[l,r]范围内被删除的比I小的数的个数,那么就用树状数组套线段树组成。

外层树状数组记录权值,内层线段树记录位置,为了节省空间,线段树动态开点(要不然二维树状数组不就好了么。。)

一开始我没有记录最开始一个数的左边比它大的数以及右边比它小的数的个数,而是动态维护,导致线段树疯狂开点,怒E。。

一次查询最多只会涉及到Log2n个节点(树状数组Logn次查询*每次查询Logn个节点),于是总共的空间是mLog2n的,完全可以接受。

如果直接动态维护一个数的左边比它大的数以及右边比它小的数的个数的话空间复杂度是O(n2)的,Terrible。。

 #include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <ctime>
#include <functional>
#define pritnf printf
#define scafn scanf
#define sacnf scanf
#define For(i,j,k) for(int i=(j);i<=(k);(i)++)
#define Clear(a) memset(a,0,sizeof(a))
using namespace std;
typedef unsigned int Uint;
const int INF=0x3fffffff;
///==============struct declaration==============
struct Seg_Node{
Seg_Node *lc,*rc;
int addv;
long long sum;
Seg_Node (){lc=rc=NULL;sum=;addv=;}
};
///==============var declaration=================
const int MAXN=;
int n,L,R,k,v,m;
long long ans=;
Seg_Node *BitTree[MAXN];
int A[MAXN],Index[MAXN],Prefix[MAXN];
int LeftGreater[MAXN],RightLess[MAXN],Bit[MAXN];
///==============function declaration============
void Add_Bit(int x);
void Add_Prefix(int x,int val);
int lowbit(int x){return x&-x;}
int Query_Prefix(int x);
long long Query_Bit(int x);
void Add_Seg(Seg_Node *&Node,int l,int r);
long long Query_Seg(Seg_Node *&Node,int l,int r,int add);
void update(Seg_Node *&Node,int l,int r);
inline void qread(int &x);
void Add_Bit(int *P,int x);
int Query_Bit(int *P,int x);
///==============main code=======================
int main()
{
//#define FILE__
#ifdef FILE__
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
qread(A[i]);
Index[A[i]]=i;k=i;v=;
Add_Prefix(i,);Add_Bit(Bit,A[i]);
LeftGreater[i]=i-Query_Bit(Bit,A[i]);
ans+=LeftGreater[i];
}
memset(Bit,,sizeof(Bit));
for(int i=n;i>=;i--){
Add_Bit(Bit,A[i]);
RightLess[i]=Query_Bit(Bit,A[i]-);
}
while (m--){
int num,pos;qread(num);pos=Index[num];
printf("%lld\n",ans);
int Left=,Right=;
ans-=LeftGreater[pos]+RightLess[pos];
L=,R=pos-;
if (L<=R)
Left=Query_Bit(n)-Query_Bit(num);
L=pos+,R=n;
if (L<=R)
Right=Query_Bit(num);
Add_Prefix(pos,-);k=pos;v=;
Add_Bit(num);
ans+=Left+Right;
}
return ;
}
///================fuction code====================
void Add_Bit(int x){
while (x<=n){
Add_Seg(BitTree[x],,n);
x+=lowbit(x);
}
}
void Add_Prefix(int x,int val){
while (x<=n){
Prefix[x]+=val;
x+=lowbit(x);
}
}
int Query_Prefix(int x){
int res=;
while (x>){
res+=Prefix[x];
x-=lowbit(x);
}
return res;
}
long long Query_Bit(int x){
long long res=;
while (x>){
res+=Query_Seg(BitTree[x],,n,);
x-=lowbit(x);
}
return res;
}
void Add_Seg(Seg_Node *&Node,int l,int r){
if (Node==NULL) Node=new(Seg_Node);
int m=(l+r)>>;
if (l==r){
Node->addv+=v;
Node->sum+=v;
return ;
}
if (m>=k) Add_Seg(Node->lc,l,m);
else Add_Seg(Node->rc,m+,r);
update(Node,l,r);
}
void update(Seg_Node *&Node,int l,int r){
Node->sum=;
if (Node->lc!=NULL) Node->sum+=Node->lc->sum;
if (Node->rc!=NULL) Node->sum+=Node->rc->sum;
Node->sum+=(r-l+)*Node->addv;
}
long long Query_Seg(Seg_Node *&Node,int l,int r,int add){
if (Node==NULL) return (r-l+)*add;
if (L<=l&&r<=R) return Node->sum+add*(r-l+);
int m=(l+r)>>;
long long Left=,Right=;
if (m>=L) Left=Query_Seg(Node->lc,l,m,add+Node->addv);
if (m<R) Right=Query_Seg(Node->rc,m+,r,add+Node->addv);
return Left+Right;
}
inline void qread(int &x){
char cha;
while(cha=getchar()) if(isdigit(cha)) break;
x=cha-'';
while(cha=getchar()){
if(!isdigit(cha)) break;
x=*x+cha-'';
}
}
void Add_Bit(int *P,int x){
while (x<=n){
P[x]++;
x+=lowbit(x);
}
}
int Query_Bit(int *P,int x){
int res=;
while (x>){
res+=P[x];
x-=lowbit(x);
}
return res;
}

BZOJ3295

【CQOI2011】动态逆序对 BZOJ3295的更多相关文章

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

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

  2. bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组

    [bzoj3295][Cqoi2011]动态逆序对 2014年6月17日4,7954 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数. ...

  3. [bzoj3295][Cqoi2011]动态逆序对_主席树

    动态逆序对 bzoj-3295 Cqoi-2011 题目大意:题目链接. 注释:略. 想法:直接建立主席树. 由于是一个一个删除,所以我们先拿建立好的root[n]的权值线段树先把总逆序对求出来,接着 ...

  4. bzoj3295[Cqoi2011]动态逆序对 树套树

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5987  Solved: 2080[Submit][Sta ...

  5. 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)

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

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

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

  7. bzoj千题计划146:bzoj3295: [Cqoi2011]动态逆序对

    http://www.lydsy.com/JudgeOnline/problem.php?id=3295 正着删除看做倒着添加 对答案有贡献的数对满足以下3个条件: 出现时间:i<=j 权值大小 ...

  8. BZOJ3295: [Cqoi2011]动态逆序对(树状数组套主席树)

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7465  Solved: 2662[Submit][Sta ...

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

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

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

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

随机推荐

  1. [LeetCode] Permutation Sequence 序列排序

    The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of the p ...

  2. Docker实践--部署Nodejs应用

    这个例子的目标是为了向大家展示如何在Docker的container里运行Node.js程序.我会先创建一个简单的Node.js web app,来构建一个镜像.然后基于这个Image运行一个cont ...

  3. underscore 源码解读之 bind 方法的实现

    自从进入七月以来,我的 underscore 源码解读系列 更新缓慢,再这样下去,今年更完的目标似乎要落空,赶紧写一篇压压惊. 前文 跟大家简单介绍了下 ES5 中的 bind 方法以及使用场景(没读 ...

  4. 调用altera IP核的仿真流程—上

    调用altera IP核的仿真流程—上 在学习本节内容之后,请详细阅读<基于modelsim-SE的简单仿真流程>,因为本节是基于<基于modelsim-SE的简单仿真流程>的 ...

  5. BZOJ 1221: [HNOI2001] 软件开发

    1221: [HNOI2001] 软件开发 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1428  Solved: 791[Submit][Stat ...

  6. 北京培训记day5

    高级数据结构 一.左偏树&斜堆 orz黄源河论文 合并,插入,删除根节点 打标记 struct Node { int fa,l,r,w,dep } tree[Mx]; int Merge(in ...

  7. Autofac 依赖注入

    介绍 Autofac是一款IOC框架,很轻量级性能非常高,自动注入很给力. NuGet Autofac:Autofac控制反转容器核心 Autofac.MVC5:提供IDependencyResolv ...

  8. dom 节点篇---模块

    改写成如下代码: var creatTag=(function(){ //var count=5; var oUl=document.createElement('ul'); var oDiv=doc ...

  9. 推荐一款Linux下的开源编辑器

    Sublime编辑器,下载地址.下载后解压,解压到家目录下,为解压后的文件夹里的可执行文件添加环境变量, vim ~/.bashrc 打开配置环境变量的文件,在最后一行添加export PATH=&q ...

  10. MAC上安装 HLA(High Level Assembly)

    1.安装HLA 最新版的hla汇编器可在这里下载,支持MacOs,Linux,Windows平台 2.安装步骤 将下载好的hla程序包放在Mac根目录下 最重要的一步是设置好环境变量,打开Mac根目录 ...