基于Manhattan最小生成树的莫队算法
点u,v的Manhattan距离:distance(u,v)= |x2-x1|+|y2-y1|
Manhattan最小生成树:边权值为两个点Manhattan距离的最小生成树。
普通算法:prim复杂度O(N2),或者处理出所有边,那么kruskal复杂度O(N2logN),这么庞大的复杂度显然是不行的
Manhattan最小生成树算法:以一个点为原点建立直角坐标系,在每45度内只会向距离该点最近的一个点连边。
简略证明:
如图,我们不妨设|AB|<=|AC|;
那么可以证明|AC|>=|BC|,证明如下
|AB|=x1+y1,|AC|=x2+y2,|BC|=|x1-x2|+|y1-y2|。而由于B和C都在y轴向右45度的区域内,有y-x>0且x>0。
下面我们分情况讨论:
- x1>x2且y1>y2。这与|AB|≤|AC|矛盾;
- x1≤x2且y1>y2。此时|BC|=x2-x1+y1-y2,|AC|-|BC|=x2+y2-x2+x1-y1+y2=x1-y1+2*y2。由前面各种关系可得y1>y2>x2>x1。假设|AC|<|BC|即y1>2*y2+x1,那 么|AB|=x1+y1>2*x1+2*y2,|AC|=x2+y2<2*y2<|AB|与前提矛盾,故|AC|≥|BC|;
- x1>x2且y1≤y2。与2同理;
- x1≤x2且y1≤y2。此时显然有|AB|+|BC|=|AC|,即有|AC|>|BC|。
综上有|AC|≥|BC|,也即在这个区域内只需选择距离A最近的点向A连边。
显然|AC|是权值最大的边,那么我们在建立最小生成树时必然不会选择它,即我们必然连接点A,B而不是A,C
接下去用kruskal算法在O(NlogN)复杂度内处理这N条边:
我们只需考虑在一块区域内的点,其他区域内的点可以通过坐标变换“移动”到这个区域内。为了方便处理,我们考虑在y轴向右45度的区域。在某个点A(x0,y0)的这个区域内的点B(x1,y1)满足x1≥x0且y1-x1>y0-x0。这里对于边界我们只取一边,但是操作中两边都取也无所谓。那么|AB|=y1-y0+x1-x0=(x1+y1)-(x0+y0)。在A的区域内距离A最近的点也即满足条件的点中x+y最小的点。因此我们可以将所有点按x坐标排序,再按y-x离散,用线段树或者树状数组维护大于当前点的y-x的最小的x+y对应的点。时间复杂度O(NlogN)。
至于坐标变换,一个比较好处理的方法是第一次直接做;第二次沿直线y=x翻转,即交换x和y坐标;第三次沿直线x=0翻转,即将x坐标取相反数;第四次再沿直线y=x翻转。注意只需要做4次,因为边是双向的。
至此,整个问题就可以在O(NlogN)的复杂度内解决了。
举例:
显然,边(i,j), (j,k), (i,k)构成一个环<i,j,k>,而(i,k)一定是最长边,可以被删去。所以我们只连边(i,j)。
为了避免重复加边,我们只考虑R1~R4这4个区域。(总共加了4N条边)
这4个区域的点(x,y)要满足什么条件?
- 如果点(x,y)在R1,它要满足:x ≥ xi ,y – x ≥ yi – xi(最近点的x + y最小)
- 如果点(x,y)在R2,它要满足:y ≥ yi ,y – x ≤ yi – xi(最近点的x + y最小)
- 如果点(x,y)在R3,它要满足:y ≤ yi ,y + x ≥ yi + xi(最近点的y – x最小)
- 如果点(x,y)在R4,它要满足:x ≥ xi ,y + x ≤ yi – xi(最近点的y – x最小)
基于Manhattan算法的莫队算法:
对于询问[l,r],我们可以将其看做一个二维平面上的点,如果询问从状态[l,r]转移到询问[l,r+1]所需时间为O(1),那么就可以用莫队算法解决。
显然询问[l1,r1]转移到询问[l2,r2]所需的时间为|l2-l1|+|r2-r1|,这时候我们可以发现这个需要的时间是两个点的Manhattan距离,
那么我们就可以用Manhattan最小生成树来优化这些所有询问之间状态转移所需的时间。
我们先对序列分块,然后以询问左端点所在的分块的序号为第一关键字,右端点的大小为第二关键字进行排序,按照排序好的顺序计算,复杂度就会大大降低。
- 分块相同时,右端点递增是
的,分块共有
个,复杂度为
- 分块转移时,右端点最多变化
,分块共有
个,复杂度为
- 分块相同时,左端点最多变化
,分块转移时,左端点最多变化
,共有
个询问,复杂度为
模板题:bzoj:小z的袜子
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- #include<cmath>
- #include<algorithm>
- #define MAXN 50005
- #define ll long long
- using namespace std;
- struct Query{
- int L,R,id;
- }q[MAXN];//所有询问
- int s,col[MAXN];//col[i]是第i个袜子的颜色
- ll ans[MAXN][],cnt[MAXN];//cnt[i]表示当前区间里颜色i出现的次数
- /*先以块为关键字从小到大排序,
- 再以右端点为关键字进行从小到大排序*/
- bool cmp(Query a,Query b){
- if(a.L/s==b.L/s) return a.R<b.R;
- return a.L/s<b.L/s;
- }
- //求最大公约数
- int gcd(ll a,ll b){
- return a?gcd(b%a,a):b;
- }
- int main(){
- int n,m;
- scanf("%d%d",&n,&m);
- s=(int)sqrt(n);
- for(int i=;i<=n;i++)
- scanf("%d",&col[i]);
- for(int i=;i<m;i++){
- int a,b;
- scanf("%d%d",&a,&b);
- q[i]=(Query){a,b,i};
- }
- sort(q,q+m,cmp);//把询问排序
- int L=,R=;
- ll res=;
- for(int i=;i<m;i++){//遍历每个询问
- while(R<q[i].R){//右边界还没拓展到q[i].R,要往右边拓展
- R++;
- res+=(cnt[col[R]]+)*(cnt[col[R]]+)-cnt[col[R]]*cnt[col[R]];
- cnt[col[R]]++;
- }
- while(L<q[i].L){//左边界超过了q[i].L,要往右边回缩
- res-=cnt[col[L]]*cnt[col[L]]-(cnt[col[L]]-)*(cnt[col[L]]-);
- cnt[col[L]]--;
- L++;
- }
- while(R>q[i].R){//右边界超过了q[i].R,要往左边回缩
- res-=cnt[col[R]]*cnt[col[R]]-(cnt[col[R]]-)*(cnt[col[R]]-);
- cnt[col[R]]--;
- R--;
- }
- while(L>q[i].L){//左边界还没拓展到q[i].L,要往左边拓展
- L--;
- res+=(cnt[col[L]]+)*(cnt[col[L]]+)-cnt[col[L]]*cnt[col[L]];
- cnt[col[L]]++;
- }
- ans[q[i].id][]=res-R+L-;//分子
- ans[q[i].id][]=(ll)(R-L+)*(R-L);//分母
- }
- for(int i=;i<m;i++){
- int G=gcd(ans[i][],ans[i][]);
- ans[i][]/=G;
- ans[i][]/=G;
- if(!ans[i][])//如果分子是0(可能出现的)
- ans[i][]=;
- }
- for(int i=;i<m;i++)
- printf("%lld/%lld\n",ans[i][],ans[i][]);
- return ;
- }
基于Manhattan最小生成树的莫队算法的更多相关文章
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 7687 Solved: 3516[Subm ...
- bzoj 2038 莫队算法
莫队算法,具体的可以看10年莫涛的论文. 大题思路就是假设对于区间l,r我们有了一个答案,那么对于区间l,r+1,我们 可以暴力的转移一个答案,那么对于区间l1,r1和区间l2,r2,需要暴力处理 的 ...
- HYSBZ2038 小Z的袜子(莫队算法)
今天学了一下传说中的解决离线询问不修改的一种算法.题目的意思非常简单,就是询问在一个[L,R]区间里的取两个物品,然后这两个物品颜色相同的概率.其实就是对于每种颜色i,这个区间里对应的个数cnt[i] ...
- bzoj 3809 Gty的二逼妹子序列(莫队算法,块状链表)
[题意] 回答若干个询问,(l,r,a,b):区间[l,r]内权值在[a,b]的数有多少[种]. [思路] 考虑使用块状链表实现莫队算法中的插入与删除. 因为权值处于1..n之间,所以我们可以建一个基 ...
- BZOJ 3236 AHOI 2013 作业 莫队算法
题目大意:给出一些数,问在一个区间中不同的数值有多少种,和在一个区间中不同的数值有多少个. 思路:因为没有改动,所以就想到了莫队算法.然后我写了5K+的曼哈顿距离最小生成树,然后果断T了.(100s的 ...
- XOR and Favorite Number(莫队算法+分块)
E. XOR and Favorite Number time limit per test 4 seconds memory limit per test 256 megabytes input s ...
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose)【莫队算法裸题&&学习笔记】
2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 9894 Solved: 4561[Subm ...
- 【国家集训队2010】小Z的袜子[莫队算法]
[莫队算法][国家集训队2010]小Z的袜子 Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程, ...
- 莫队算法详解和c实现
解析和实现 摘要: 莫队算法是一个对于区间.树或其他结构离线(在线)维护的算法,此算法基于一些基本算法,例如暴力维护,树状数组,分块,最小曼哈顿距离生成树,对其进行揉合从而产生的一个简单 ...
随机推荐
- 【mmall】url-pattern配置为"/"和"/*"的区别
我的代码 <!-- springmvc --> <servlet> <servlet-name>springmvc</servlet-name> < ...
- MVC_Route层层深入
1.前期准备 新建一个MVC项目,并添加Home和About两个控制器 在这两个控制器对应添加index页面 namespace Study_MVC_Route.Controllers { publi ...
- Setup Objective UI with UMG
创建UI蓝图控件 拖入一个文本框 新建一个Actor,继承自FPSHUD 创建控件,并显示到界面上 新建一个Actor,继承FPSGameMode 将属性里的HUD更改为之前创建的 在世界设置中,将G ...
- python - zipfile模块
import zipfile # f=zipfile.ZipFile(filename, mode="r", compression=ZIP_STORED, allowZip64= ...
- synchronized底层实现原理&CAS操作&偏向锁、轻量级锁,重量级锁、自旋锁、自适应自旋锁、锁消除、锁粗化
进入时:monitorenter 每个对象有一个监视器锁(monitor).当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:1 ...
- ASP.NET MVC - WEB API
ASP.NET WEB API 与WEB API有关的类型 HttpMessageHandler(System.Net.Http)(消息处理器) 表示Http请求的处理程序,处理程序类似于Http管道 ...
- 6034 Balala Power! (17多校)
题目大意:给出的字符串,每个字符建立一种与0-25的对应关系.然后每个字符串看成是一个26进制的数.问能获得的数的总和的最大值.(最后对1e9+7取模). 题目思考:把每个字符的贡献值看做一个26进制 ...
- mybatis resultType resultMap 区别
resultType 就是返回的类型 resultMap 返回的是一个结果集,这个结果集一般是用过resultMap节点来配置的,相应的type一般是一个Model. https://blog.csd ...
- 不指定虚拟路径的前提下通过http访问pdf、图片等文件
通常我们通过http访问图片或者pdf的时候都是将文件上传到指定文件夹下面,然后通过配置虚拟路径来访问指定的资源. 在不配置虚拟路径的情况下,我们通过获取到response的outpurstream, ...
- 构建高性能WEB站点之 吞吐率、吞吐量、TPS、性能测试
内容参考: 构建高性能WEB站点.pdf 一.吞吐率 我们一般使用单位时间内服务器处理的请求数来描述其并发处理能力.称之为吞吐率(Throughput),单位是 “req/s”.吞吐率特指Web服务器 ...