[BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树
3295: [Cqoi2011]动态逆序对
Time Limit: 10 Sec Memory Limit: 128 MB
Description
Input
Output
Sample Input
1
5
3
4
2
5
1
4
2
Sample Output
2
2
1
样例解释
(1,5,3,4,2) (1,3,4,2) (3,4,2) (3,2) (3)。
HINT
N<=100000 M<=50000
题解:
啊啊啊这道题真的是差点把自己打死
跟zyfdalao分享了一下思路然后他就按我的思路A了可是我自己却不会了
如果你是树套树玩家,请移步:http://www.cnblogs.com/TSHugh/p/7001884.html
在具体写题解之前,我要分享一个面对瓶颈很好的做法(我这样反复理了三遍,思路一遍比一遍清晰...遇到瓶颈的时候真的很推荐这样做):
思路不通了把所有已知条件再列出来一边,写清变量之间的关系和限制,并且针对每一个条件写出解决方案和打法
感觉凌乱的代码段就删掉重打一遍,用的总时间一定会比死调下去少
首先一个小优化:把val变成n-val+1,这样原来的逆序对就变成了现在的顺序对,个人感觉更加好操作.
我们考虑,我们可以利用树状数组求出一开始总的逆序对数,并且同时利用树状数组求出以每个位置为开头和结尾的逆序对个数,
我们设num数组表示这个数目,num[0][i]表示以i位置结尾的逆序对个数,num[1][i]表示以i位置开头的逆序对个数.
这样的话,每次我们先输出当前的总数,再减去num[0][i]+num[1][i],然后...
我们发现有一些不对,如果原来形成的逆序对的另外那个数已经被删除了,那么这一对就不应该被减去
所以我们考虑再计算一个delta表示这个增量:
其中delta[0][i]表示以i位置结尾,但是另外那个数比i删除的早的逆序对个数,
delta[1][i]表示以i位置开头,但是另外那个数比i删除的早的逆序对个数.
接下来我们考虑什么样的数对(i,j)会被记入delta
如果设i位置的数的删除时间是tim[i](没有被删除的数的删除时间顺次设成m+1~n即可,他们的delta不会被记入答案)
设i位置的数值是val[i](这里的val已经进行了n-val+1取反操作)
那么delta[0][i]里的数应该满足:
tim[i]>tim[j]
val[i]>val[j]
i>j
delta[1][i]里的数应该满足:
tim[i]>tim[j]
val[i]<val[j]
i<j
那么上面这两组约束条件(尤其是第一组)很像一个三维偏序的统计问题.
的确如此,我们只需要用CDQ分治统计一下符合条件的数对数即可.
拿我的思路来说,我们可以让时间有序,给下标排序,用树状数组维护权值val,
这样跑两遍CDQ统计符合条件的偏序对数,就能分别计算delta[0][i]和delta[1][i]
最后输出答案时,先输出答案ans,然后给ans减去num[0][i]+num[1][i],再加上delta[0][i]+delta[1][i],这样就能正确的维护逆序对数了,
代码实现:
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=,M=;
struct node
{
int tim,val,pos;
node (int a=,int b=,int c=){tim=a,val=b,pos=c;}
}q[N];
int cnt,n,m,a[N],match[N],step[M];
bool vis[N];
LL delta[][N],num[][N],bit[N];
inline int lowbit(int a){return a&-a;}
inline void add(int a,LL b)
{while(a<=n)bit[a]+=b,a+=lowbit(a);}
inline LL sum(int a)
{LL ret=;while(a)ret+=bit[a],a-=lowbit(a);return ret;}
inline void gsum0()
{
for(register int i=;i<=n;++i)
num[][i]=sum(a[i]),add(a[i],);
memset(bit,,sizeof(bit));
}
inline void gsum1()
{
for(register int i=n;i;--i)
num[][i]=sum(a[i]),add(,),add(a[i],-);
memset(bit,,sizeof(bit));
}
inline void readin()
{
register int i;scanf("%d%d",&n,&m);
for(i=;i<=n;++i)
scanf("%d",&a[i]),a[i]=n-a[i]+,match[a[i]]=i;
gsum0();gsum1();
for(i=;i<=m;++i)
scanf("%d",&step[i]),step[i]=n-step[i]+,vis[step[i]]=;
}
inline bool mt1(const node &a,const node &b){return a.pos<b.pos;}
inline bool mt2(const node &a,const node &b){return a.tim<b.tim;}
inline void CDQ0(int l,int r)
{
if(l==r)return;
register int mi=l+r>>,i;
CDQ0(l,mi);CDQ0(mi+,r);
sort(q+l,q+r+,mt1);
for(i=l;i<=r;++i)
if(q[i].tim<=mi)add(q[i].val,);
else delta[][q[i].tim]+=sum(q[i].val);
for(i=l;i<=r;++i)
if(q[i].tim<=mi)add(q[i].val,-);
}
inline void CDQ1(int l,int r)
{
if(l==r)return;
register int mi=l+r>>,i;
CDQ1(l,mi);CDQ1(mi+,r);
sort(q+l,q+r+,mt1);
for(i=r;i>=l;--i)
if(q[i].tim<=mi)add(,),add(q[i].val,-);
else delta[][q[i].tim]+=sum(q[i].val);
for(i=r;i>=l;--i)
if(q[i].tim<=mi)add(,-),add(q[i].val,);
}
int main()
{
register int i;readin();
for(i=;i<=m;++i)
q[++cnt]=node(cnt,step[i],match[step[i]]);
for(i=;i<=n;++i)
if(!vis[a[i]])q[++cnt]=node(cnt,a[i],i);
CDQ0(,n),sort(q+,q+n+,mt2),CDQ1(,n);
LL ans=;int pos;
for(i=;i<=n;++i)ans+=num[][i];
for(i=;i<=m;++i)
{
printf("%lld\n",ans),pos=match[step[i]],
ans-=(num[][pos]+num[][pos]),
ans+=(delta[][i]+delta[][i]);
}
}
[BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树的更多相关文章
- 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 ...
- BZOJ3295:[CQOI2011]动态逆序对(CDQ分治)
Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...
- 【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治
[BZOJ3295][Cqoi2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依 ...
- bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组
[bzoj3295][Cqoi2011]动态逆序对 2014年6月17日4,7954 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数. ...
- 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)
3295: [Cqoi2011]动态逆序对 **Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j& ...
- [BZOJ3295] [Cqoi2011]动态逆序对(带修改主席树)
题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序 ...
- [CQOI2011]动态逆序对 CDQ分治
洛谷上有2道相同的题目(基本是完全相同的,输入输出格式略有不同) ---题面--- ---题面--- CDQ分治 首先由于删除是很不好处理的,所以我们把删除改为插入,然后输出的时候倒着输出即可 首先这 ...
- 洛谷 P3157 [CQOI2011]动态逆序对 | CDQ分治
题目:https://www.luogu.org/problemnew/show/3157 题解: 1.对于静态的逆序对可以用树状数组做 2.我们为了方便可以把删除当成增加,可以化动为静 3.找到三维 ...
随机推荐
- Gitlab 403 forbidden 并发引起IP被封
问题 在工作中自搭建的Gitlab.但今天打开页面的时候显示的是空白页面,上面还有一次文本Forbidden. 原因 Gitlab使用rack_attack做了并发访问的限制. 解决方案 将Gitla ...
- 可道云kodexplorer搭建私有云后的配置优化
一.上传下载速度优化首先明确可道云没有对上传下载做任何限制,速度快慢和网络环境有关.可道云是基于http上传,所以和其他http上传速度基本一致:可以对比其他web系统或网站说附件上传速度.同其他例如 ...
- Ansible 连接主机显示报错的处理方案
一.在ansible安装完毕后一般需要以SSH的方式连接到需要进行管理的目标主机,一开始遇到了如下问题: 192.168.15.4 | UNREACHABLE! => { "ch ...
- 获400 万美元 A 轮融资,ShipBob 想帮助小微企业享受Amazon Prime 级配送服务 2016-06-18
Weiss认为,无论零售市场的发展走向如何波动,ShipBob公司都能够获得坚实的成长表现. 在线销售实体商品的小型企业当然希望利用种种方式取悦客户,但面对着Amazon Prime迅如闪电且价格实惠 ...
- [译文]c#扩展方法(Extension Method In C#)
原文链接: https://www.codeproject.com/Tips/709310/Extension-Method-In-Csharp 介绍 扩展方法是C# 3.0引入的新特性.扩展方法使你 ...
- ffmpeg——压缩mav格式音频
今天偶然帮朋友压缩一个mav格式的音频.开始用压缩码率的方式,mav格式的音频体积一点都没变,查资料需要压缩音频文件的采样率和声道才能压缩mav格式的音频. 压缩要求是:将一个mav格式的音频文件,由 ...
- OO第四阶段总结
一.测试与正确性论证的区别 从哲学的角度来说,正确性论证与测试的关系就像理论与实践的关系一样. 使用测试的方法检验程序正确性确实是一个非常方便可行且广泛运用的方法.可以通过几个简单或复杂的测试样例,迅 ...
- 课堂讨论—Alpha版总结会议
我们在课堂上针对第一阶段冲刺过程中存在的问题,展开了激烈的讨论,并投票选出需要改进的最主要三个问题. 有图有真相:
- 《Spring2之站立会议6》
<Spring2之站立会议6> 昨天,向主界面中加入语音功能部分的代码: 今天,查相关资料解决debug: 遇到问题,一些问题是得到解决了,但是一些还未被解决.
- Git初用心得
第一次使用git,因为之前操作系统的实验需要,在虚拟机中使用过lniux系统,所以对这种用指令输入而不是图形化的程序感觉不是很陌生.感觉git还是很人性化的,git gui就是图形界面,操作起来也不复 ...