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. .NET跨平台之旅:corehost 是如何加载 coreclr 的

    在前一篇博文中,在好奇心的驱使下,探秘了 dotnet run ,发现了神秘的 corehost  —— 运行 .NET Core 应用程序的幕后英雄.有时神秘就是一种诱惑,神秘的 corehost ...

  2. Java反射机制

    Java反射机制 一:什么事反射机制 简单地说,就是程序运行时能够通过反射的到类的所有信息,只需要获得类名,方法名,属性名. 二:为什么要用反射:     静态编译:在编译时确定类型,绑定对象,即通过 ...

  3. Redis 常用操作

    import org.junit.Before;import org.junit.Test;import redis.clients.jedis.Jedis;import java.util.Set; ...

  4. mysql Packet for query is too large (1185 > 1024)异常

    注:最近mysql一直提示如下错误 Packet for query is too large (1185 > 1024). You can change this value on the s ...

  5. maven

    maven常见问题问答 1.前言 Maven,发音是[`meivin],"专家"的意思.它是一个很好的项目管理工具,很早就进入了我的必备工具行列,但是这次为了把project1项目 ...

  6. C#-WebForm-点击网页中的按钮后跳转到其他页面是怎么实现的?

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. javascript json字符串与对象相互转换

    在实际项目中,经常遇到字符格式的问题,记下来以便日后方便查看.用到两个函数:JSON.stringify() 和 JSON.parse(). 使用ajax向后台请求数据,后台给前端返回数据,明明后端脚 ...

  8. 分享10条PHP性能优化的小技巧,帮助你更好的用PHP开发:

    1. foreach效率更高,尽量用foreach代替while和for循环. 2. 循环内部不要声明变量,尤其是对象这样的变量. 3. 在多重嵌套循环中,如有可能,应当将最长的循环放在内层,最短循环 ...

  9. WA题集

    #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> ...

  10. 如果mac电脑的usb转接器连接wlan时不显示,也就是不识别usb此时的网络连接没有,解决办法就是如下

    1.接上电源   关机 先按下shift +ctrl + opt + 开机键    ,等待10秒,这10秒是没有反应的,屏幕不会亮,系统不会跑起来,  10秒之后松开所有键,再按下opt + cmd ...