【BZOJ3295】【CQOI2011】动态逆序对

cdq分治经典例题,然而智商掉线傻逼错误坑了两天

原题:

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

N<=100000 M<=50000

此题修改和询问绑定完全离线,可以直接倒序变成插入,然后就是三维数星星辣(? ?????)?

x为下标,y为值,z为时间轴,x排序,z_cdq分治,y树状数组

不用搞两次cdq分治,每次按x递增查找比y大的,然后按x递减查找比y小的

注意当x递增的时候查找的是比y大的,因为虽然x是递增,但是修改上去的都是比当前x小的

然后我先计算贡献再把小于mid的放左边大于mid的放右边然后进入下一层的做法是没有问题的

问题在于我傻逼题中删除的是值我删的是下标

注意longlong

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<vector>
 8 using namespace std;
 9 #define ll long long
10 int read(){int z=0,mark=1;  char ch=getchar();
11     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)mark=-1;  ch=getchar();}
12     while(ch>=‘0‘&&ch<=‘9‘){z=(z<<3)+(z<<1)+ch-‘0‘;  ch=getchar();}
13     return z*mark;
14 }
15 struct cdd{int x,y,z;}a[110000],q[110000];
16 int n,m,b[110000];  int N;
17 bool usd[110000];  int tt=0;
18 ll e[110000];  int lbt[110000];
19 ll ans[110000];
20 int re[110000];
21 void gtlbt(){for(int i=1;i<=n;++i)  lbt[i]=i&-i;}
22 void mdf(int x,int y){while(x<=n)  e[x]+=y,x+=lbt[x];}
23 ll qr(int x){ll bwl=0;  while(x)  bwl+=e[x],x-=lbt[x];  return bwl;}
24 void cdq(int l,int r){
25     if(l==r)  return ;
26     int md=(l+r)>>1;
27     for(int i=l;i<=r;++i){
28         if(a[i].z>md)  mdf(a[i].y,1);
29         else  ans[a[i].z]+=qr(n)-qr(a[i].y);
30     }
31     for(int i=l;i<=r;++i)if(a[i].z>md)  mdf(a[i].y,-1);
32     for(int i=r;i>=l;--i){
33         if(a[i].z>md)  mdf(a[i].y,1);
34         else  ans[a[i].z]+=qr(a[i].y);
35     }
36     for(int i=l;i<=r;++i)if(a[i].z>md)  mdf(a[i].y,-1);
37     int t1=l,t2=md+1;
38     for(int i=l;i<=r;++i)  q[(a[i].z<=md?t1:t2)++]=a[i];
39     for(int i=l;i<=r;++i)  a[i]=q[i];
40     cdq(l,md),cdq(md+1,r);
41 }
42 bool cmp(cdd x,cdd y){return x.x<y.x;}
43 int main(){//freopen("ddd.in","r",stdin);
44     memset(usd,0,sizeof(usd));
45     cin>>n>>m;  N=n-m;
46     gtlbt();
47     for(int i=1;i<=n;++i)  b[i]=read(),re[b[i]]=i;
48     for(int i=1;i<=m;++i)  a[++tt].y=read(),a[i].x=re[a[i].y],a[i].z=i,usd[a[i].x]=true;
49     for(int i=1;i<=n;++i)if(!usd[i])  a[++tt].x=i,a[tt].y=b[i],a[tt].z=tt;
50     sort(a+1,a+n+1,cmp);
51     cdq(1,n);
52     for(int i=n;i>1;--i)  ans[i-1]+=ans[i];
53     for(int i=1;i<=m;++i)  printf("%I64d\n",ans[i]);
54     return 0;
55 }

时间: 2024-08-27 15:20:02

【BZOJ3295】【CQOI2011】动态逆序对的相关文章

[bzoj3295][Cqoi2011][动态逆序对] (树套树)

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample Input 5 4 1 5 3

[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

【分块】bzoj3295 [Cqoi2011]动态逆序对

考虑每次删除pos位置一个数x后,所造成的的影响就是,逆序对的个数少了在1~pos-1中大于x的数的个数加上pos+1~n中小于x的数的个数. 那么我们需要的操作就只有查询区间内比某数大(小)的个数. ↑,分块经典操作,每个块里维护一个有序表. 由于有删除,最好每个块用一个vector. 对于原数列怎么办呢?只需要弄一个vis数组,vis[i]表示i位置的数已经删除即可.(要找到v在原数列中的位置的话,在其所在块暴力即可.) 查询时对整块二分,对要删的元素所在块分成两段暴力. O(n*sqrt(

BZOJ3295 CQOI2011 动态逆序对 树状数组套线段树

离线倒着做,每次加入一个节点后新增的逆序对数量就是其左边大于它的数的个数(左边数的总数-左边小于它的数的个数)+右边小于它的数的个数 用树状数组维护求和,对于树状数组中每个节点v所对应的区间线段树维护区间[l,r]中大于v的数的个数. 最后唯一的问题就是指针版线段树MLE-- #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <alg

BZOJ3295: [Cqoi2011]动态逆序对 莫队

这个用莫队做会被卡,但是我还是...... 收获在于树状数组维护后缀和以及双维排序...... 莫队的时间复杂度比想象中的要好一些.... 然而我还是被卡了...... #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define MAXN 100005 using namespace std; int pos[M

bzoj3295: [Cqoi2011]动态逆序对 三维数点

为了便于考虑,把删除反序变为增加 于是就变成关于权值和位置和时间的三维数点 一波cdq一波树状数组教做人 (神TM需要longlong,80了一发) 1 #include <bits/stdc++.h> 2 #define mid (l+r>>1) 3 #define ll long long 4 using namespace std; 5 ll n,ret,m,tem; 6 ll tr[200001],a[200001],in[200001]; 7 bool ok[200001

【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治

[BZOJ3295][Cqoi2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的

[CQOI2011]动态逆序对

P1347 - [CQOI2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数. 以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个

主席树初探 &amp; bzoj 3295: [Cqoi2011] 动态逆序对 题解

[原题] 3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 778  Solved: 263 [Submit][Status] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元

【BZOJ 3295】 [Cqoi2011]动态逆序对

3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1373  Solved: 465 [Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数