BZOJ 3295: [Cqoi2011]动态逆序对 cdq分治

https://www.lydsy.com/JudgeOnline/problem.php?id=3295

这个妹妹我曾见过的~~~

之前应该在校内oj写了,似乎还写过题解?发现没写博客就重新水一遍代码水一篇博客好了。

把找逆序对的过程想成一个一个往里塞数字然后找每个数字可以组成的逆序对,把最后要去掉的几个也想成往里塞,所以加一个时间维度用cdq求三维偏序。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 #define LL long long
 9 #define pa pair<int,int>
10 const int maxn=100010;
11 const LL minf=(LL)5e17;
12 int n,m;
13 struct nod{
14     int t,id,v;LL ans;
15 }a[maxn];
16 int b[maxn]={},vis[maxn]={};
17 LL t[maxn]={}; int sta[maxn]={},tai=0;
18 priority_queue< pa , vector< pa > , greater< pa > >q[2];
19
20 inline void addt(int x,int v){ while(x<=n){ t[x]+=v; x+=(x&-x); } }
21 inline LL gett(int x){ LL tsn=0; while(x){ tsn+=t[x]; x-=(x&-x); } return tsn; }
22 bool mcmp1(nod aa,nod bb){
23     if(aa.id!=bb.id)return aa.id<bb.id;
24     return aa.t<bb.t;
25 }
26 bool mcmp2(nod aa,nod bb){
27     if(aa.t!=bb.t)return aa.t<bb.t;
28     return aa.id<bb.id;
29 }
30 void doit(int l,int r){
31     if(l==r)return;
32     int mid=(l+r)/2;
33     doit(l,mid); doit(mid+1,r);
34     //x被查找y查找
35     for(int i=l;i<=mid;i++)q[0].push(make_pair(a[i].t,i));
36     for(int i=mid+1;i<=r;i++)q[1].push(make_pair(a[i].t,i));
37     tai=0;
38     while(!q[1].empty()){
39         pa y=q[1].top(); q[1].pop();
40         if(q[0].empty()){a[y.second].ans+=gett(n)-gett(a[y.second].v);continue;} pa x=q[0].top();
41         while(x.first<=y.first){
42             addt(a[x.second].v,1); sta[++tai]=a[x.second].v;
43             q[0].pop(); if(q[0].empty())break; x=q[0].top();
44         }a[y.second].ans+=gett(n)-gett(a[y.second].v);
45     }
46     while(!q[0].empty())q[0].pop();
47     for(int i=1;i<=tai;i++)addt(sta[i],-1);
48
49     for(int i=l;i<=mid;i++)q[0].push(make_pair(a[i].t,i));
50     for(int i=mid+1;i<=r;i++)q[1].push(make_pair(a[i].t,i));
51     tai=0;
52     while(!q[0].empty()){
53         pa y=q[0].top(); q[0].pop();
54         if(q[1].empty()){a[y.second].ans+=gett(a[y.second].v-1);continue;} pa x=q[1].top();
55         while(x.first<=y.first){
56             addt(a[x.second].v,1); sta[++tai]=a[x.second].v;
57             q[1].pop(); if(q[1].empty())break; x=q[1].top();
58         }a[y.second].ans+=gett(a[y.second].v-1);
59     }
60     while(!q[1].empty())q[1].pop();
61     for(int i=1;i<=tai;i++)addt(sta[i],-1);
62 }
63 int main(){
64     scanf("%d%d",&n,&m);
65     for(int i=1;i<=n;i++){scanf("%d",&a[i].v);a[i].id=i;a[i].t=i;vis[a[i].v]=i;}
66     for(int i=1;i<=m;i++){scanf("%d",&b[i]);a[vis[b[i]]].t=n+m+1-i;}
67     sort(a+1,a+1+n,mcmp1); doit(1,n);
68     sort(a+1,a+1+n,mcmp2);
69     for(int i=2;i<=n;i++)a[i].ans+=a[i-1].ans;
70     for(int i=1;i<=m;i++)printf("%lld\n",a[n-i+1].ans);
71     return 0;
72 }

原文地址:https://www.cnblogs.com/137shoebills/p/9060496.html

时间: 2024-10-11 21:47:13

BZOJ 3295: [Cqoi2011]动态逆序对 cdq分治的相关文章

主席树初探 &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]动态逆序对(树套树 or CDQ分治)

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

bzoj 3295: [Cqoi2011]动态逆序对

2016-06-22 这个题本想昨天晚上做来,但昨晚狂风大作,暴雨倾盆(听说我们学校最落后的一堵墙都被吹到了),停电了,我只能无聊的瞭望了教学楼一晚上...... 这个题把删除看成插入的话,插入一个点 新增逆序对就是比他早插入的,位置靠前,数比他大或 位置靠后,数比他小.那这就是个三维偏序集,可以用CDQ搞搞了. 这个题也能用树套树,树状数组归并排序做(以后有时间要写一写,恐怕是没可能了%>_<%). 1 #include<cstdio> 2 #include<iostrea

COGS 1715 &amp; bzoj 3295 [CQOI2011]动态逆序对 题解

(又是一道树套树……自己真是玩疯了……) (题意略) 从网上也看过题解,好像解法很多……比如CDQ+树状数组,树状数组套主席树,树状数组套平衡树……我用的是树状数组套splay. (我会说是因为我不会写CDQ和树状数组套主席树么= =) (不得不吐槽,为啥splay这么快= =) 也没啥可说的,我写的是在线算法,只要在删除一个元素之前统计它前面比它大的数和后面比它小的数的个数(区间求和用树状数组,统计比它小/大的数的个数用平衡树写),把答案减掉对应数值即可. 鉴于这题卡常,我就加了快读和各种in

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

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

P3157 [CQOI2011]动态逆序对(CDQ分治)

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

LUOGU P3157 [CQOI2011]动态逆序对(CDQ 分治)

传送门 解题思路 cdq分治,将位置看做一维,修改时间看做一维,权值看做一维,然后就转化成了三维偏序,用排序+cdq+树状数组.注意算删除贡献时要做两次cdq,分别算对前面和后面的贡献. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 100005; const int MAXM =

BZOJ 3295 [Cqoi2011]动态逆序对 树状数组套线段树

题意:链接 方法:树状数组套线段树 解析: 这题基本上写的都是什么CDQ点分治,主席树之类的,然而这我都并不会,所以写了一发平衡树套线段树想卡时卡过去,然而我并没有得逞,T的不要不要的,这里用平衡树套线段树的方法参见我的题解:排队.这道题比那道更要简单. 然后我就打算弃坑了~不过看140142做这道题做的热火朝天的,还是打算回来做一下,yy下树状数组套线段树,然后去看hz的题解,只看懂他写理论部分了,代码部分不知所云,所以还是还是得yy.引用理论部分. 删除某个数,只要统计它之前还存在的比它大的