[BZOJ3295] [Cqoi2011]动态逆序对(带修改主席树)
题目描述
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
输入输出格式
输入格式:
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
输出格式:
输出包含m行,依次为删除每个元素之前,逆序对的个数。
输入输出样例
5 4
1
5
3
4
2
5
1
4
2
5
2
2
1 样例解释
(1,5,3,4,2),(1,3,4,2),(3,4,2),(3,2),(3)。
说明
N<=100000 M<=50000
题解
原来还以为自己已经会带修改主席树了呢……才发现自己还是太naive……
然后找到的题解全是CDQ分治的……我这个蒟蒻有点方……
然后发现还是zcysky大佬写的最吼啦
还是来详细的说一说
先考虑无修改的逆序对怎么做?
很明显,用树状数组(虽然我今天之前一直以为逆序对个数只能用归并做)
我们记$a1[i]$表示在$i$之前且比$i$大的数的个数(注意,这里的i指的是位置),那么很明显答案为$\sum _{i=1}^n a[i]$
代码实现
for(int i=;i<=n;++i){
val[i]=read(),pos[val[i]]=i;
a1[i]=ask(n)-ask(val[i]);
ans+=a1[i];
for(int j=val[i];j<=n;j+=lowbit(j)) ++c[j];
}
记$a2[i]$表示在$i$之后且比$i$小的数的个数,只要把上面那个倒着推就行了
for(int i=n;i;--i){
a2[i]=ask(val[i]-);
for(int j=val[i];j<=n;j+=lowbit(j)) ++c[j];
}
接下来我们考虑修改操作。
每一次将一个数删除,减少的逆序对个数是多少?
很明显是$a1[i]+a2[i]$,然后我们就可以做啦
于是评测机表示并不想理你并丢给你一堆WA
这个时候我们发现自己忽略了一个关键的问题,如果$a1[i]$和$a2[i]$中表示的数已经有被删除了的怎么办?
我们只要把这些被删除的数减去即可
具体来说,我们可以考虑用一个带修改主席树维护
因为主席树维护的是前缀和
如果按照一般思想,一个一个去更改太浪费时间了
我们想到,前缀和可以用树状数组的思想来维护
于是我们可以用树状数组的思想建主席树
于是每一次更改就可以减少到做$log n$次了
所以每一次删去一个数,我们就在主席树上插入这个数
要算答案时,只要减去$a1[i]$和$a2[i]$,再把删除的数加回来就好了
只要在主席树上$[1,i-1]$区间中大于$val[i]$的数的个数和$[i+1,n]$区间中小于$val[i]$的数的个数即可
//minamoto
#include<bits/stdc++.h>
#define N 100005
#define M 5000005
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline ll read(){
#define num ch-'0'
char ch;bool flag=;ll res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char obuf[<<],*o=obuf;
void print(ll x){
if(x>) print(x/);
*o++=x%+;
}
int L[M],R[M],sum[M],rt[N];
int val[N],pos[N],xx[N],yy[N],c[N],a1[N],a2[N];
int n,cnt,q;ll ans=;
inline int lowbit(int x){return x&(-x);}
int ask(int x){
int s=;
for(int i=x;i;i-=lowbit(i)) s+=c[i];
return s;
}
void update(int &now,int l,int r,int k){
if(!now) now=++cnt;
++sum[now];
if(l==r) return;
int mid=(l+r)>>;
if(k<=mid) update(L[now],l,mid,k);
else update(R[now],mid+,r,k);
}
int querysub(int x,int y,int v){
int cntx=,cnty=,ans=;--x;
for(int i=x;i;i-=lowbit(i)) xx[++cntx]=rt[i];
for(int i=y;i;i-=lowbit(i)) yy[++cnty]=rt[i];
int l=,r=n;
while(l<r){
int mid=(l+r)>>;
if(v<=mid){
for(int i=;i<=cntx;++i) ans-=sum[R[xx[i]]];
for(int i=;i<=cnty;++i) ans+=sum[R[yy[i]]];
for(int i=;i<=cntx;++i) xx[i]=L[xx[i]];
for(int i=;i<=cnty;++i) yy[i]=L[yy[i]];
r=mid;
}
else{
for(int i=;i<=cntx;++i) xx[i]=R[xx[i]];
for(int i=;i<=cnty;++i) yy[i]=R[yy[i]];
l=mid+;
}
}
return ans;
}
int querypre(int x,int y,int v){
int cntx=,cnty=,ans=;--x;
for(int i=x;i;i-=lowbit(i)) xx[++cntx]=rt[i];
for(int i=y;i;i-=lowbit(i)) yy[++cnty]=rt[i];
int l=,r=n;
while(l<r){
int mid=(l+r)>>;
if(v>mid){
for(int i=;i<=cntx;++i) ans-=sum[L[xx[i]]];
for(int i=;i<=cnty;++i) ans+=sum[L[yy[i]]];
for(int i=;i<=cntx;++i) xx[i]=R[xx[i]];
for(int i=;i<=cnty;++i) yy[i]=R[yy[i]];
l=mid+;
}
else{
for(int i=;i<=cntx;++i) xx[i]=L[xx[i]];
for(int i=;i<=cnty;++i) yy[i]=L[yy[i]];
r=mid;
}
}
return ans;
}
int main(){
//freopen("testdata.in","r",stdin);
n=read(),q=read();
for(int i=;i<=n;++i){
val[i]=read(),pos[val[i]]=i;
a1[i]=ask(n)-ask(val[i]);
ans+=a1[i];
for(int j=val[i];j<=n;j+=lowbit(j)) ++c[j];
}
memset(c,,sizeof(c));
for(int i=n;i;--i){
a2[i]=ask(val[i]-);
for(int j=val[i];j<=n;j+=lowbit(j)) ++c[j];
}
while(q--){
print(ans),*o++='\n';
int x=read();x=pos[x];
ans-=(a1[x]+a2[x]-querysub(,x-,val[x])-querypre(x+,n,val[x]));
for(int j=x;j<=n;j+=lowbit(j)) update(rt[j],,n,val[x]);
}
fwrite(obuf,o-obuf,,stdout);
return ;
}
[BZOJ3295] [Cqoi2011]动态逆序对(带修改主席树)的更多相关文章
- [luogu3157][bzoj3295][CQOI2011]动态逆序对【cdq分治+树状数组】
题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序 ...
- 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)
3295: [Cqoi2011]动态逆序对 **Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j& ...
- BZOJ3295: [Cqoi2011]动态逆序对(树状数组套主席树)
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 7465 Solved: 2662[Submit][Sta ...
- BZOJ3295 [Cqoi2011]动态逆序对 —— CDQ分治
题目链接:https://vjudge.net/problem/HYSBZ-3295 3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 1 ...
- bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组
[bzoj3295][Cqoi2011]动态逆序对 2014年6月17日4,7954 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数. ...
- bzoj3295: [Cqoi2011]动态逆序对(cdq分治+树状数组)
3295: [Cqoi2011]动态逆序对 题目:传送门 题解: 刚学完cdq分治,想起来之前有一道是树套树的题目可以用cdq分治来做...尝试一波 还是太弱了...想到了要做两次cdq...然后伏地 ...
- bzoj3295[Cqoi2011]动态逆序对 树套树
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5987 Solved: 2080[Submit][Sta ...
- [BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j,且 ...
- bzoj千题计划146:bzoj3295: [Cqoi2011]动态逆序对
http://www.lydsy.com/JudgeOnline/problem.php?id=3295 正着删除看做倒着添加 对答案有贡献的数对满足以下3个条件: 出现时间:i<=j 权值大小 ...
随机推荐
- NinePatch图片
绍 参考 :http://blog.sina.com.cn/s/blog_5033827f0100r4dm.html NinePatch图片以*.9.png结尾,和普通图片的区别是四周多了一个边框(如 ...
- (转)小谈keepalived vip漂移原理与VRRP协议
背景:之前搭建过keepalived双机热备的集群,但对其中的原理不甚理解,看完就忘了,所有有必要深入的学习下. 简介 什么是keepalived呢?keepalived是实现高可用的一种轻量级的技术 ...
- (转)Maven仓库——私服介绍
背景:对Maven私服一直想做个深入的总结,因为不了解,所以感觉很陌生. 转载地址:http://blog.csdn.net/catoop/article/details/62312477 常用功能和 ...
- ACCESS与SQL Server下SQL Like 查询的不同
在ACCESS中LIKE的用法Access里like的通配符用法是这样: “?”表示任何单一字符: “*”表示零个或多个字符: “#”表示任何一个数字 所以应该是: select * from dat ...
- 在 CentOS 6.x 上安装最新版本的 git
在 CentOS 的默认仓库中有git,所以最简单的方法是: $ sudo yum install git 这种方法虽然简单,但是一般仓库里的版本更新不及时,比如 CentOS 仓库中的 git 最新 ...
- JS面试题(二)(常见算法编程)
1.字符串转驼峰 例如:border-bottom-color ----> borderBottomColor var str="border-bottom-color"; ...
- Ansible playbook 批量修改服务器密码 先普通后root用户
fsckzy Ansible playbook 批量修改服务器密码 客户的需求:修改所有服务器密码,密码规则为Rfv5%+主机名后3位 背景:服务器有CentOS6.7,SuSE9.10.11,r ...
- 在Win10中,在安装msi安装包的时候常常会出现代码为2502、2503的错误。
前言:在Win10中,在安装msi安装包的时候常常会出现代码为2502.2503的错误.其实这种错误是由于安装权限不足造成的,可以这种msi的安装包不像其他exe的安装程序,在安装包上点击“右键”之后 ...
- Tensorflow-gpu版本安装
目录 服务器选型 NVIDIA GPU驱动安装 cuda和cudnn的安装 cuda安装 cudnn的安装 tensorflow-gpu安装 最近给公司部署一套深度学习相关的环境,以tensorflo ...
- oracle先排序再分页
只做简单记录 按操作时间排序1 SELECT A.*, ROWNUM RN FROM (SELECT * FROM v_log) A ORDER BY operatetime DESC 结果 可以发现 ...