[BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树)

题面

给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数

分析

每次都对整个序列求逆序对显然不行,考虑每次删除对逆序对个数的影响

假如删除的数为x,x在序列中的位置为pos[x],那么包含x的逆序对个数为位置在[1,pos[x]-1]中大于x的数+位置在[pos[x]+1,n]中小于x的数,每次删除只要减去这些就可以了

那么这个问题其实就转化成查询位置在[L,R]内,且值域在[l,r]内的数的个数。本质上和带修区间第k大BZOJ 1901 Dynamic Rankings是一样的,外层用树状数组维护位置,内层不用可持久化,直接用权值线段树即可

那么我们像树状数组那样维护n棵权值线段树,不同的是每棵权值线段树里保存的是,a[i-lowbit(i)+1]~a[i]有多少个值落在区间[l,r]内

对于查询[ql,qr]中有多少个值时的做差

我们要像树状数组求和那样,把root[i],root[i-lowbit(i)],....共O(logn)棵权值线段树的值加起来,才能得到a[1]a[i]有多少个数落在1qr里面,1~(ql-1)同理,维护两个临时数组x,y存储这O(logn)棵权值线段树的根即可

对于单点修改,我们像树状数组修改那样,往O(logn)棵权值线段树中插入即可

时间复杂度\(O(m \log ^2 n)\),常数略大

注意答案一定要开long long!!!!

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100000
#define maxm 100000
#define maxnlogn 50000000
#define maxlogn 20
using namespace std;
inline void qread(int &x) {
x=0;
int sign=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
inline void qprint(long long x) {
if(x<0) {
putchar('-');
qprint(-x);
} else if(x==0) {
putchar('0');
return;
} else {
if(x>=10) qprint(x/10);
putchar('0'+x%10);
}
} int n,m;
int a[maxn+5];
struct segment_tree_val{
#define lson(x) (tree[x].ls)
#define rson(x) (tree[x].rs)
struct node{
int ls;
int rs;
int v;
}tree[maxnlogn+5];
int ptr;
void push_up(int x){
tree[x].v=tree[lson(x)].v+tree[rson(x)].v;
}
void update(int &x,int upos,int uval,int l,int r){
if(!x) x=++ptr;
if(l==r){
tree[x].v+=uval;
return;
}
int mid=(l+r)>>1;
if(upos<=mid) update(tree[x].ls,upos,uval,l,mid);
else update(tree[x].rs,upos,uval,mid+1,r);
push_up(x);
}
int totx,toty;
int x[maxn+5],y[maxn+5];
int query_less(int k,int l,int r){//查询<k的数的个数
int cnt=0;
while(l!=r){
int mid=(l+r)>>1;
if(k<=mid){
for(int i=1;i<=totx;i++) x[i]=lson(x[i]);
for(int i=1;i<=toty;i++) y[i]=lson(y[i]);
r=mid;
}else{
for(int i=1;i<=totx;i++) cnt-=tree[lson(x[i])].v;
for(int i=1;i<=toty;i++) cnt+=tree[lson(y[i])].v;
for(int i=1;i<=totx;i++) x[i]=rson(x[i]);
for(int i=1;i<=toty;i++) y[i]=rson(y[i]);
l=mid+1;
}
}
return cnt;
}
int query_more(int k,int l,int r){//查询>k的数的个数
int cnt=0;
while(l!=r){
int mid=(l+r)>>1;
if(k<=mid){
for(int i=1;i<=totx;i++) cnt-=tree[rson(x[i])].v;
for(int i=1;i<=toty;i++) cnt+=tree[rson(y[i])].v;
for(int i=1;i<=totx;i++) x[i]=lson(x[i]);
for(int i=1;i<=toty;i++) y[i]=lson(y[i]);
r=mid;
}else{
for(int i=1;i<=totx;i++) x[i]=rson(x[i]);
for(int i=1;i<=toty;i++) y[i]=rson(y[i]);
l=mid+1;
}
}
return cnt;
}
}T1; struct fenwick_tree{
inline int lowbit(int x){
return x&(-x);
}
int root[maxn+5];
void update(int t2pos,int t1pos,int val){
for(int i=t2pos;i<=n;i+=lowbit(i)){
T1.update(root[i],t1pos,val,1,n);
}
}
int query_less(int lpos,int rpos,int val){
T1.totx=T1.toty=0;
for(int i=lpos-1;i;i-=lowbit(i)) T1.x[++T1.totx]=root[i];
for(int i=rpos;i;i-=lowbit(i)) T1.y[++T1.toty]=root[i];
return T1.query_less(val,1,n);
}
int query_more(int lpos,int rpos,int val){
T1.totx=T1.toty=0;
for(int i=lpos-1;i;i-=lowbit(i)) T1.x[++T1.totx]=root[i];
for(int i=rpos;i;i-=lowbit(i)) T1.y[++T1.toty]=root[i];
return T1.query_more(val,1,n);
}
}T2; int pos[maxn+5];
long long ans=0;
int main(){
// freopen("4.in","r",stdin);
// freopen("4.out","w",stdout);
// freopen("1.txt","r",stdin);
int x;
qread(n);
qread(m);
for(int i=1;i<=n;i++){
qread(a[i]);
pos[a[i]]=i;
ans+=T2.query_more(1,i-1,a[i]);
T2.update(i,a[i],1);
}
qprint(ans);
putchar('\n');
for(int i=1;i<m;i++){
qread(x);
ans-=T2.query_more(1,pos[x]-1,x);
ans-=T2.query_less(pos[x]+1,n,x);
qprint(ans);
putchar('\n');
T2.update(pos[x],x,-1);
}
}
/*
5 4
1 5 3 4 2
5
1
4
2 */

[BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)的更多相关文章

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

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

  2. luogu P3157 [CQOI2011]动态逆序对(CDQ分治)

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

  3. Luogu P3157 [CQOI2011]动态逆序对

    题目链接 \(Click\) \(Here\) 这个题有点卡常数..我的常数比较大所以是吸着氧气跑过去的... 题意:计算对于序列中每个位置\(p\),\([1,p-1]\)区间内比它大的数的个数,和 ...

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

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

  5. BZOJ - 2141 排队 (动态逆序对,区间线段树套权值线段树)

    题目链接 交换两个数的位置,只有位于两个数之间的部分会受到影响,因此只需要考虑两个数之间有多少数对a[l]和a[r]产生的贡献发生了变化即可. 感觉像是个带修改的二维偏序问题.(修改点$(x,y)$的 ...

  6. bzoj 3295 (洛谷3157、3193) [Cqoi2011]动态逆序对——树套树 / CDQ分治

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3295 题目--洛谷3157:https://www.luogu.org/problemnew ...

  7. [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)

    [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...

  8. BZOJ 3295: [Cqoi2011]动态逆序对

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

  9. Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2886  Solved: 924[Submit][Stat ...

随机推荐

  1. DOM-document 对象

    Document 对象Document 对象代表整个HTML 文档,可用来访问页面中的所有元素.Document 对象是 Window 对象的一个部分,可通过 window.document 属性来访 ...

  2. postman(三):详解postman动态变量使用

    参考: Variables Dynamic variables

  3. Azure IoT 技术研究系列1

    物联网技术已经火了很多年了,业界各大厂商都有各自成熟的解决方案.我们公司主要搞新能源汽车充电,充电桩就是我们物联网技术的最大应用,车联网.物联网. 互联网三网合一.作为Azure重要的Partner和 ...

  4. Python---进阶---logging---装饰器打印日志2

    ### logging - logging.debug - logging.info - logging.warning - logging.error - logging.critical ---- ...

  5. SpringCloud学习系列-Eureka服务注册与发现(4)

    actuator与注册微服务信息完善 1.主机名称:服务名称修改 当前问题 含有主机名称 修改修改microservicecloud-provider-dept-8001 的yml文件 修改内容 eu ...

  6. 【leetcode】1154. Day of the Year

    题目如下: Given a string date representing a Gregorian calendar date formatted as YYYY-MM-DD, return the ...

  7. 关了浏览器再开,怎么session还在?

    关了浏览器session当然仍然存在,因为session是储存在服务器端的,而服务器是不可能知道你有没有关掉浏览器. 服务器只是简单的保持session接受用户请求,只有当session一段时间没有被 ...

  8. phpstudy升级5.7

    1:备份当前数据库数据. 最好是导成 SQL 文件 2:备份 PhpStudy 下的 MySQL 文件夹.以防升级失败.还可以使用旧版本的数据库 3:下载MySQL5.7.解压.然后放在 PhpStu ...

  9. BP神经网络设计

    1.网络层数 大部分单个隐藏层即可 2.输入层神经元个数 输入变量的个数通常都是由问题的外部描述所确定的.例如,如果有4个外部变量作为网络的输入,那么网络就有4个输入.但是,这是不是意味着输入层的神经 ...

  10. volley简介

    究竟什么是volley呢?  在以前的开发过程中,开发app的时候,使用的东西可能包括: 1.Httpclient,HttpURLConnection 2.AsyncTask,AsyncTaskLoa ...