luogu P3157 [CQOI2011]动态逆序对(CDQ分治)
题目描述
对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
输入输出格式
输入格式:
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
输出格式:
输出包含m行,依次为删除每个元素之前,逆序对的个数。
题解
我们发现一个数的贡献,就是就是t'<t(删除时间),xb'<xb(下标),w'>w(权值)的数的数量和t'>t,xb'>xb,w'<w的数的数量之和。
这就是一个三维偏序类型的题,所以做两遍CDQ分治分别的到这两种贡献。最后用总逆序对数减去就好了。
1A真开心。。。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
const long long N=;
long long n,m,a[N],b[N],tmp,tr[N],ans[N],book[N],ma[N],tot;
struct query{
long long id,xb,w;
}q[N],c[N];
bool cmp(query a,query b){
return a.id>b.id;
}
void gb(long long l,long long r){
if(l==r)return;
long long mid=(l+r)>>;
gb(l,mid);
gb(mid+,r);
long long ll=l;
long long lr=mid+;
long long cnt=;
while(ll<=mid&&lr<=r){
cnt++;
if(a[ll]<a[lr]){
b[cnt]=a[ll++];
}
else{
b[cnt]=a[lr++];
tmp+=mid-ll+;
}
}
while(ll<=mid)b[++cnt]=a[ll++];
while(lr<=r)b[++cnt]=a[lr++];
for(long long i=l;i<=r;i++){
a[i]=b[i-l+];
}
}
long long lowbit(long long x){
return x&-x;
}
void add(long long x,long long w){
for(long long i=x;i<=n;i+=lowbit(i)){
tr[i]+=w;
}
}
long long getsum(long long x){
long long ans=;
for(long long i=x;i>=;i-=lowbit(i)){
ans+=tr[i];
}
return ans;
}
void cdq(long long l,long long r){
if(l==r)return;
long long mid=(l+r)>>;
cdq(l,mid);cdq(mid+,r);
long long ll=l;long long rl=mid+;long long now=;
while(ll<=mid&&rl<=r){
if(q[ll].xb<q[rl].xb){
add(q[ll].w,);
c[++now]=q[ll++];
}
else{
ans[q[rl].id]+=getsum(n)-getsum(q[rl].w);
c[++now]=q[rl++];
}
}
while(ll<=mid){
add(q[ll].w,);
c[++now]=q[ll++];
}
while(rl<=r){
ans[q[rl].id]+=getsum(n)-getsum(q[rl].w);
c[++now]=q[rl++];
}
for(long long i=l;i<=mid;i++)add(q[i].w,-);
for(long long i=l;i<=r;i++)q[i]=c[i-l+];
}
void CDQ(long long l,long long r){
if(l==r)return;
long long mid=(l+r)>>;
CDQ(l,mid);CDQ(mid+,r);
long long ll=l;long long rl=mid+;long long now=;
while(ll<=mid&&rl<=r){
if(q[ll].xb>q[rl].xb){
add(q[ll].w,);
c[++now]=q[ll++];
}
else{
ans[q[rl].id]+=getsum(q[rl].w);
c[++now]=q[rl++];
}
}
while(ll<=mid){
add(q[ll].w,);
c[++now]=q[ll++];
}
while(rl<=r){
ans[q[rl].id]+=getsum(q[rl].w);
c[++now]=q[rl++];
}
for(long long i=l;i<=mid;i++)add(q[i].w,-);
for(long long i=l;i<=r;i++)q[i]=c[i-l+];
}
int main(){
scanf("%lld%lld",&n,&m);
for(long long i=;i<=n;i++){
scanf("%lld",&a[i]);
ma[a[i]]=i;
}
for(long long i=;i<=m;i++){
long long x;
scanf("%lld",&x);
q[i].id=i;q[i].xb=ma[x];q[i].w=x;
book[ma[x]]=;
}
tot=m;
for(long long i=;i<=n;i++){
if(book[i]==){
q[++tot].id=m+;q[tot].xb=i;q[tot].w=a[i];
}
}
sort(q+,q+n+,cmp);
cdq(,n);
sort(q+,q+n+,cmp);
CDQ(,n);
gb(,n);
for(long long i=;i<=m;i++){
printf("%lld\n",tmp);
tmp-=ans[i];
}
return ;
}
luogu P3157 [CQOI2011]动态逆序对(CDQ分治)的更多相关文章
- LUOGU P3157 [CQOI2011]动态逆序对(CDQ 分治)
传送门 解题思路 cdq分治,将位置看做一维,修改时间看做一维,权值看做一维,然后就转化成了三维偏序,用排序+cdq+树状数组.注意算删除贡献时要做两次cdq,分别算对前面和后面的贡献. #inclu ...
- 洛谷 P3157 [CQOI2011]动态逆序对 | CDQ分治
题目:https://www.luogu.org/problemnew/show/3157 题解: 1.对于静态的逆序对可以用树状数组做 2.我们为了方便可以把删除当成增加,可以化动为静 3.找到三维 ...
- P3157 [CQOI2011]动态逆序对 CDQ分治
一道CDQ分治模板题简单来说,这道题是三维数点对于离线的二维数点,我们再熟悉不过:利用坐标的单调递增性,先按更坐标排序,再按纵坐标排序更新和查询时都直接调用纵坐标.实际上,我们是通过排序将二维中的一维 ...
- P3157 [CQOI2011]动态逆序对 (CDQ解决三维偏序问题)
P3157 [CQOI2011]动态逆序对 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任 ...
- [BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树
3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j,且 ...
- 【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治
[BZOJ3295][Cqoi2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依 ...
- bzoj3295: [Cqoi2011]动态逆序对(cdq分治+树状数组)
3295: [Cqoi2011]动态逆序对 题目:传送门 题解: 刚学完cdq分治,想起来之前有一道是树套树的题目可以用cdq分治来做...尝试一波 还是太弱了...想到了要做两次cdq...然后伏地 ...
- BZOJ3295 [Cqoi2011]动态逆序对 —— CDQ分治
题目链接:https://vjudge.net/problem/HYSBZ-3295 3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec Memory Limit: 1 ...
- [Luogu P3157][CQOI2011]动态逆序对 (树套树)
题面 传送门:[CQOI2011]动态逆序对 Solution 一开始我看到pty巨神写这套题的时候,第一眼还以为是个SB题:这不直接开倒车线段树统计就完成了吗? 然后冷静思考了一分钟,猛然发现单纯的 ...
随机推荐
- svn创建分支的做法
作者:朱金灿 来源:http://blog.csdn.net/clever101 1. 首先选择你要创建分支的工作目录,如下图: 2.选择要创建分支的路径.注释以及版本,选择HEADrevision ...
- 【算法】Dijkstra算法(单源最短路径问题)(路径还原) 邻接矩阵和邻接表实现
Dijkstra算法可使用的前提:不存在负圈. 负圈:负圈又称负环,就是说一个全部由负权的边组成的环,这样的话不存在最短路,因为每在环中转一圈路径总长就会边小. 算法描述: 1.找到最短距离已确定的顶 ...
- Java中如何解决线程安全问题
给出一个问题,如下: 解决方案如下: public class Demo_5 { public static void main(String[] args) { //创建一个窗口 TicketWin ...
- php截取字符串|php截取字符串前几位|php截取中文字符串
转 截取字符串专题:php截取字符串函数,php 字符串长度,php截取字符串前几位 PHP截取中文字符串(mb_substr)和获取中文 => http://www.q3060.com/lis ...
- Msql免安装版安装
文首提要: 我下载的MySQL版本是:mysql-5.7.17-winx64.zip Archive版:系统:Windows7 64位. 一.解压文件 下载好MySQL后, ...
- Java Class文件结构
此文件格式为JAVA7的格式,可能与JAVA6 CLASS不一致. 每一个Class都对应着唯一的一个类或借口的定义信息.这里,我们称为"Class文件格式"只是通俗的将任意一个符 ...
- redhat 7 cenos 7 网络配置文件
Cenos 7 TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no DEFROUTE=yes IPV4_FAILURE_FATAL=no NAME=eth0 ...
- MySQL 数据还原
1.1还原使用mysqldump命令备份的数据库的语法如下: mysql -u root -p [dbname] < backup.sq 示例: mysql -u root -p < C: ...
- Qt之QThread
简述 QThread类提供了与系统无关的线程. QThread代表在程序中一个单独的线程控制.线程在run()中开始执行,默认情况下,run()通过调用exec()启动事件循环并在线程里运行一个Qt的 ...
- HDU 5274(LCA + 线段树)
Dylans loves tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...