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] Delete Duplicate Emails 删除重复邮箱

    Write a SQL query to delete all duplicate email entries in a table named Person, keeping only unique ...

  2. Android开发之import org.apache.http

    在build.gradle(app)中添加一下依赖: android { useLibrary 'org.apache.http.legacy' } dependencies { compile 'o ...

  3. 【C#】新建服务自动发送邮件

    ---windows服务,---自动发送邮件 邮件发送code #region 发送邮件函数 public void SendMailUseZj() { System.Net.Mail.MailMes ...

  4. mysqlbinlog抽取某个表的信息

    http://blog.163.com/zhao_jw/blog/static/180587366201110293630648/

  5. 学习ASP.NET 5和MVC6

    今天很荣幸的参加了微软开源跨平台讲座,充分认识了下一个版本的ASP.NET所带来的激动人心的特性.虽然过去已经断断续续的了解了一些ASP.NET5和MVC6与EF7的动态,但是都没有这一次来的系统化( ...

  6. 【Codeforces 738A】Interview with Oleg

    http://codeforces.com/contest/738/problem/A Polycarp has interviewed Oleg and has written the interv ...

  7. Beta阶段第七次Scrum Meeting

    Beta阶段第七次Scrum Meeting 情况简述 BETA阶段第七次Scrum Meeting 敏捷开发起始时间 2016/12/20 00:00 敏捷开发终止时间 2016/12/21 00: ...

  8. bzoj 4320: ShangHai2006 Homework

    4320: ShangHai2006 Homework Time Limit: 10 Sec Memory Limit: 128 MB Description 1:在人物集合 S 中加入一个新的程序员 ...

  9. NOIP2016游记

    只是游记而已.流水账. Day0:忘了. Day1:看完T1,本以为T2一如既往很简单,结果看了半天完全没有思路.然后看了一眼T3,期望,NOIP什么时候要考期望了,于是接着看T2.一开始我推的限制条 ...

  10. Premiere使用整理

    整理部分自己在使用Premiere CC中遇到的问题和注意点. 1. 新建序列 若是录屏文件,可选择已加入到项目中的视频文件,点击 文件-新建-来自剪辑的序列. 2. 新建字幕 用于在视频中添加文字. ...