[CQOI2011]动态逆序对

P1347 - [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

4

2
5
1

4

2

Sample Output

5

2

2

1

Hint

样例解释

(1,5,3,4,2)?(1,3,4,2)?(3,4,2)?(3,2)?(3)。

数据规模:

N<=100000 , M<=50000

pre.cjk { font-family: "Droid Sans Fallback", monospace }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

把删除看成插入,将每个点赋予一个插入时间,则i的逆序对要满足的条件为:位置在i前,值比i大,时间比i小;或者位置在i后,值比i小,时间比i小。然后就可以用sort+CDQ+树状数组维护三维偏序,注意每个时间的答案要加上前面时间的答案。
  1 #include<set>
  2 #include<map>
  3 #include<queue>
  4 #include<stack>
  5 #include<ctime>
  6 #include<cmath>
  7 #include<string>
  8 #include<vector>
  9 #include<cstdio>
 10 #include<cstdlib>
 11 #include<cstring>
 12 #include<iostream>
 13 #include<algorithm>
 14 #define maxn 100010
 15 using namespace std;
 16 struct data{
 17   int x,y,z,ans1,ans2;
 18 }f[maxn];
 19 int tree[maxn],co[maxn],LOL=0;
 20 long long ans[maxn];
 21 int lowbit(int x){return x&-x;}
 22 void add(int p,int v){
 23   for(int i=p;i<maxn;i+=lowbit(i)){
 24     if(co[i]!=LOL) tree[i]=0;
 25     co[i]=LOL;
 26     tree[i]+=v;
 27   }
 28 }
 29 int find(int p){
 30   int ret=-0;
 31   for(int i=p;i;i-=lowbit(i))
 32     if(co[i]==LOL) ret+=tree[i];
 33   return ret;
 34 }
 35 bool cmpcdq1(const data &a,const data &b){
 36   if(a.y!=b.y) return a.y>b.y;
 37   else return a.z<b.z;
 38 }
 39 bool cmpcdq2(const data &a,const data &b){
 40   if(a.y!=b.y) return a.y<b.y;
 41   else return a.z<b.z;
 42 }
 43 void CDQ1(int l,int r){
 44   if(l==r) return;
 45   int mid=(l+r)>>1;
 46   CDQ1(l,mid),CDQ1(mid+1,r);
 47   sort(f+l,f+mid+1,cmpcdq1),sort(f+mid+1,f+r+1,cmpcdq1);
 48   LOL++;
 49   for(int j=mid+1,i=l;j<=r;j++){
 50     for(;f[i].y>f[j].y&&i<=mid;i++)
 51       add(f[i].z,1);
 52     f[j].ans1+=find(f[j].z);
 53   }
 54 }
 55 void CDQ2(int l,int r){
 56   if(l==r) return;
 57   int mid=(l+r)>>1;
 58   CDQ2(l,mid),CDQ2(mid+1,r);
 59   sort(f+l,f+mid+1,cmpcdq2),sort(f+mid+1,f+r+1,cmpcdq2);
 60   LOL++;
 61   for(int j=mid+1,i=l;j<=r;j++){
 62     for(;f[i].y<f[j].y&&i<=mid;i++)
 63       add(f[i].z,1);
 64     f[j].ans2+=find(f[j].z);
 65   }
 66 }
 67 bool cmmp(const data &a,const data &b){
 68   return a.y<b.y;
 69 }
 70 bool cmmmp(const data &a,const data &b){
 71   return a.x<b.x;
 72 }
 73 bool cmmmp1(const data &a,const data &b){
 74   return a.x>b.x;
 75 }
 76 int main()
 77 {
 78   freopen("!.in","r",stdin);
 79   freopen("!.out","w",stdout);
 80   int n,m,sp;scanf("%d%d",&n,&m);
 81   for(int i=1;i<=n;i++)
 82     scanf("%d",&f[i].y),f[i].x=i;
 83   sort(f+1,f+n+1,cmmp);
 84   int cnt=m+1;
 85   for(int i=1;i<=m;i++)
 86     scanf("%d",&sp),f[sp].z=cnt,cnt--;
 87   for(int i=1;i<=n;i++)
 88     if(!f[i].z)f[i].z=1;
 89   sort(f+1,f+n+1,cmmmp);
 90   CDQ1(1,n);
 91   LOL=0;memset(co,0,sizeof(co));
 92   sort(f+1,f+n+1,cmmmp1);
 93   CDQ2(1,n);
 94   for(int i=1;i<=n;i++)
 95     ans[f[i].z]+=f[i].ans1+f[i].ans2;
 96   ans[1]/=2;
 97   for(int i=2;i<=m+1;i++)
 98     ans[i]+=ans[i-1];
 99   for(int i=m+1;i>=2;i--)
100     printf("%lld\n",ans[i]);
101   return 0;
102 }

 
时间: 2024-08-04 21:46:49

[CQOI2011]动态逆序对的相关文章

主席树初探 &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,即初始元素的个数和删除的元

【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行,依次为删除每个元素之前,逆序对的

【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,即初始元素的个数

P3157 [CQOI2011]动态逆序对

P3157 [CQOI2011]动态逆序对 https://www.luogu.org/problemnew/show/P3157 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. 输入输出格式 输入格式: 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次

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

题面 传送门:[CQOI2011]动态逆序对 Solution 一开始我看到pty巨神写这套题的时候,第一眼还以为是个SB题:这不直接开倒车线段树统计就完成了吗? 然后冷静思考了一分钟,猛然发现单纯的线段树并不能解决这个问题,好像还要在外面再套上一颗树. 这就很shit了.你问我资磁不资磁树套树,我是不资磁的,树套树是暴力数据结构,我能资磁吗? 很不幸,昨天现实狠狠地打了我一脸:时间不够开新坑的,不切题又浑身难受,找了半天题,还是把这道题拉了出来(哈,真香) 不扯淡了,这题还是很显然的. 考虑开

题解 P3157 【[CQOI2011]动态逆序对】

题目链接 Solution [CQOI2011]动态逆序对 题目大意:给定一个\(n\)个数的排列,依次删除\(m\)个元素,询问删除每个元素之前的逆序对数量 分析:对于这种依次删除元素的问题,我们的通常解法是时间倒流,顺序删除变逆序插入,那么问题就转化为了每插入一个数之后(对应删除之前)询问逆序对数量. 我们设元素\(i\)的时间戳为\(T_i\)(对于那些没有被删除的元素,\(T_i = 0\)),位置为\(P_i\),权值为\(V_i\) 那么,如果插入元素\(j\)后,元素\(i\)与元

P3157 [CQOI2011]动态逆序对 (CDQ解决三维偏序问题)

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

[CQOI2011]动态逆序对(主席树,树状数组)

[CQOI2011]动态逆序对(luogu) 题目描述 对于序列 aa,它的逆序对数定义为集合 \{(i,j)| i<j \wedge a_i > a_j \}{(i,j)∣i<j∧ai?>aj?} 中的元素个数. 现在给出 1\sim n1∼n 的一个排列,按照某种顺序依次删除 mm 个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. 输入格式 第一行包含两个整数 nn 和 mm,即初始元素的个数和删除的元素个数.以下 nn 行,每行包含一个 1 \sim n1∼n

[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