热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[BZOJ3295][Cqoi2011]动态逆序对CDQ分治&树套树

3295:[Cqoi2011]动态逆序对Description对于序列A,它的逆序对数定义为满足iAj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除

3295: [Cqoi2011]动态逆序对

Time Limit: 10 Sec  Memory Limit: 128 MB

Description

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

Input

输入第一行包含两个整数nm,即初始元素的个数和删除的元素个数。以下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

样例解释
(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]

i

那么上面这两组约束条件(尤其是第一组)很像一个三维偏序的统计问题.

的确如此,我们只需要用CDQ分治统计一下符合条件的数对数即可.

拿我的思路来说,我们可以让时间有序,给下标排序,用树状数组维护权值val,

这样跑两遍CDQ统计符合条件的偏序对数,就能分别计算delta[0][i]和delta[1][i]

最后输出答案时,先输出答案ans,然后给ans减去num[0][i]+num[1][i],再加上delta[0][i]+delta[1][i],这样就能正确的维护逆序对数了,

代码实现:

 1 #include 
 2 #include 
 3 #include 
 4 using namespace std;
 5 typedef long long LL;
 6 const int N=100010,M=50010;
 7 struct node
 8 {
 9     int tim,val,pos;
10     node (int a=0,int b=0,int c=0){tim=a,val=b,pos=c;}
11 }q[N];
12 int cnt,n,m,a[N],match[N],step[M];
13 bool vis[N];
14 LL delta[2][N],num[2][N],bit[N];
15 inline int lowbit(int a){return a&-a;}
16 inline void add(int a,LL b)
17     {while(a<=n)bit[a]+=b,a+=lowbit(a);}
18 inline LL sum(int a)
19     {LL ret=0;while(a)ret+=bit[a],a-=lowbit(a);return ret;}
20 inline void gsum0()
21 {
22     for(register int i=1;i<=n;++i)
23         num[0][i]=sum(a[i]),add(a[i],1);
24     memset(bit,0,sizeof(bit));
25 }
26 inline void gsum1()
27 {
28     for(register int i=n;i;--i)
29         num[1][i]=sum(a[i]),add(1,1),add(a[i],-1);
30     memset(bit,0,sizeof(bit));
31 }
32 inline void readin()
33 {
34     register int i;scanf("%d%d",&n,&m);
35     for(i=1;i<=n;++i)
36         scanf("%d",&a[i]),a[i]=n-a[i]+1,match[a[i]]=i;
37     gsum0();gsum1();
38     for(i=1;i<=m;++i)
39         scanf("%d",&step[i]),step[i]=n-step[i]+1,vis[step[i]]=1;
40 }
41 inline bool mt1(const node &a,const node &b){return a.pos<b.pos;}
42 inline bool mt2(const node &a,const node &b){return a.tim<b.tim;}
43 inline void CDQ0(int l,int r)
44 {
45     if(l==r)return;
46     register int mi=l+r>>1,i;
47     CDQ0(l,mi);CDQ0(mi+1,r);
48     sort(q+l,q+r+1,mt1);
49     for(i=l;i<=r;++i)
50         if(q[i].tim<=mi)add(q[i].val,1);
51         else delta[0][q[i].tim]+=sum(q[i].val);
52     for(i=l;i<=r;++i)
53         if(q[i].tim<=mi)add(q[i].val,-1);
54 }
55 inline void CDQ1(int l,int r)
56 {
57     if(l==r)return;
58     register int mi=l+r>>1,i;
59     CDQ1(l,mi);CDQ1(mi+1,r);
60     sort(q+l,q+r+1,mt1);
61     for(i=r;i>=l;--i)
62         if(q[i].tim<=mi)add(1,1),add(q[i].val,-1);
63         else delta[1][q[i].tim]+=sum(q[i].val);
64     for(i=r;i>=l;--i)
65         if(q[i].tim<=mi)add(1,-1),add(q[i].val,1);
66 }
67 int main()
68 {
69     register int i;readin();
70     for(i=1;i<=m;++i)
71         q[++cnt]=node(cnt,step[i],match[step[i]]);
72     for(i=1;i<=n;++i)
73         if(!vis[a[i]])q[++cnt]=node(cnt,a[i],i);
74     CDQ0(1,n),sort(q+1,q+n+1,mt2),CDQ1(1,n);
75     LL ans=0;int pos;
76     for(i=1;i<=n;++i)ans+=num[0][i];
77     for(i=1;i<=m;++i)
78     {
79         printf("%lld\n",ans),pos=match[step[i]],
80         ans-=(num[0][pos]+num[1][pos]),
81         ans+=(delta[0][i]+delta[1][i]);
82     }
83 }

[BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树


推荐阅读
  • 22.Container With Most Water(能装最多水的容器)
    thecontainercontainsthemos ... [详细]
  • 2019.4.14第1001题:SumProblemProblemDescriptionHey,welcometoHDOJ(HangzhouDianziUniversityOnli ... [详细]
  • 本文分析和介绍了GLo ... [详细]
  • spotify engineering culture part 1
    原文,因为原视频说的太快太长,又没有字幕,于是借助youtube,把原文听&打出来了。中文版日后有时间再翻译。oneofthebigsucceessfactorshereatSpo ... [详细]
  • MyBatis模糊查询和多条件查询一、ISmbmsUserDao层根据姓名模糊查询publicListgetUser();多条件查询publicList ... [详细]
  • Xib九宫格应用管理使用xib封装一个自定义view的步骤1新建一个继承UIView的自定义view,假设类名叫做(AppView)2新建一个AppView.xib文件来描述 ... [详细]
  • 简单动态字符串redis里面很多地方都用到了字符串,我们知道redis是一个键值对存储的非关系型数据库,那么所有的key都是用字符串存储的,还有字符串类型,这些都是用字符串存储的 ... [详细]
  • 例子如Table表有性别字段,1代表男2代表女、3代表中性、还有没填就代表未说明selectid,decode(sex,'1','男', ... [详细]
  • C#的Type对象的简单应用
    通过Type对象可以获取类中所有的公有成员直接贴代码:classMyClass{privatestringname;privateintid;publicstringcity;pu ... [详细]
  • rbac 4表 常规设计
    rbac4表常规设计设计模型:1、管理员表(users)Schema::create('users',function(Blueprint$table){$tabl ... [详细]
  • 代码:在mysql5.6,运行正常,5.7报错SELECTsum((selecta.numwherea.status1))astotalFROMmes_order_productA ... [详细]
  • 以SOA服务为导向的信息系统构建是通过有计划地构建信息系统时,一种简单而有柔性的方法,就是组件化与服务导向架构。过去的信息系统,是在使用者需要新功能时才开发的,也就是响应不同时 ... [详细]
  • 接口测试的方式有很多,比如可以用工具(jmeter,postman)之类,也可以自己写代码进行接口测试,工具的使用相对来说都比较简单,重点是要搞清楚项目接口的协议是什么,然后有针对 ... [详细]
  • 作业迁移
    背景:数据库服务器更换,1、数据库迁移(BACKUPRESTORE);2、数据库登录名用户迁移(注意孤立用户);3、作业迁移数据库迁移,备份数据库、拷贝备份文件到新服务器,还原数据 ... [详细]
  • 定义:定义两个数论函数\(f\)、\(g\)的Dirichlet卷积为:\[\left(f*g\right)\left(n\right)\sum_{d|n}f\left(d\rig ... [详细]
author-avatar
修成书君4212
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有