[BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)
[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]动态逆序对(树状数组套权值线段树)的更多相关文章
- [Luogu P3157][CQOI2011]动态逆序对 (树套树)
题面 传送门:[CQOI2011]动态逆序对 Solution 一开始我看到pty巨神写这套题的时候,第一眼还以为是个SB题:这不直接开倒车线段树统计就完成了吗? 然后冷静思考了一分钟,猛然发现单纯的 ...
- luogu P3157 [CQOI2011]动态逆序对(CDQ分治)
题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序 ...
- Luogu P3157 [CQOI2011]动态逆序对
题目链接 \(Click\) \(Here\) 这个题有点卡常数..我的常数比较大所以是吸着氧气跑过去的... 题意:计算对于序列中每个位置\(p\),\([1,p-1]\)区间内比它大的数的个数,和 ...
- LUOGU P3157 [CQOI2011]动态逆序对(CDQ 分治)
传送门 解题思路 cdq分治,将位置看做一维,修改时间看做一维,权值看做一维,然后就转化成了三维偏序,用排序+cdq+树状数组.注意算删除贡献时要做两次cdq,分别算对前面和后面的贡献. #inclu ...
- BZOJ - 2141 排队 (动态逆序对,区间线段树套权值线段树)
题目链接 交换两个数的位置,只有位于两个数之间的部分会受到影响,因此只需要考虑两个数之间有多少数对a[l]和a[r]产生的贡献发生了变化即可. 感觉像是个带修改的二维偏序问题.(修改点$(x,y)$的 ...
- bzoj 3295 (洛谷3157、3193) [Cqoi2011]动态逆序对——树套树 / CDQ分治
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3295 题目--洛谷3157:https://www.luogu.org/problemnew ...
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
- BZOJ 3295: [Cqoi2011]动态逆序对
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3865 Solved: 1298[Submit][Sta ...
- Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2886 Solved: 924[Submit][Stat ...
随机推荐
- VMmare下安装redhat
一.虚拟机必须安装在自定义的文件夹下,虚拟硬盘文件必须存放在自定义路径下(避免中文) 二.安装时选择linux类型时必须选择red hat enterprise linux 5 64位 三.操作系统名 ...
- day5 函数
1.求全部元素的和 [1,2,1,2,3,3,3,3] 遍历 a = [1,2,1,2,3,3,3,3] sum = 0 n = len(a)-1 while n>=0: sum += a[ ...
- 运行biggan demo
http://www.zhuanzhi.ai/document/8705953a704e1bf8e051c161d1587d88
- 移动web开发之像素和DPR详解
前话: 像素在web开发中几乎天天用到,但到底什么是像素,移动端和桌面端的像素有区别吗,缩放对像素有影响吗,视网膜屏幕和像素有什么关系?关于这些问题,可能就不清楚了.本文将介绍关于像素的相关知识 什么 ...
- Vue 基于node npm & vue-cli & element UI创建vue单页应用
基于node npm & vue-cli & element UI创建vue单页应用 开发环境 Win 10 node-v10.15.3-x64.msi 下载地址: https ...
- web上传大文件(>4G)有什么解决方案?
众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路. 实现文件夹 ...
- CF786B Legacy 线段树优化建图 + spfa
CodeForces 786B Rick和他的同事们做出了一种新的带放射性的婴儿食品(???根据图片和原文的确如此...),与此同时很多坏人正追赶着他们.因此Rick想在坏人们捉到他之前把他的遗产留给 ...
- 个推安卓推送SDK集成步骤详解
以下是一位开发者在集成个推安卓推送SDK时候的亲身经历: 作者:吃饱了想睡. 概述 公司准备采用个推作为第三方推送平台,我作为客户端的头号小鸟,掐指一算已经毕业 0.1 年了,Leader 准备把这个 ...
- nf_conntrack: table full, dropping packet解决方法
https://blog.csdn.net/yanggd1987/article/details/45886913
- Visual Studio Code - 在 JS 源码(TS、压缩前代码)上使用断点
步骤: 在构建工具(webpack.gulp 等)的配置中开启生成 source map 将 VSCode 配置中的debug.allowBreakpointsEverywhere设置为true(重要 ...