基于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实现
解析和实现 摘要: 莫队算法是一个对于区间.树或其他结构离线(在线)维护的算法,此算法基于一些基本算法,例如暴力维护,树状数组,分块,最小曼哈顿距离生成树,对其进行揉合从而产生的一个简单 ...
随机推荐
- day 4 - 1 列表
1.列表的增删改查 1) append insert extend li = ["ysg",[1,2,3,4,5],"peipei","梦幻" ...
- C - Kite URAL - 1963 (几何+四边形判断对称轴)
题目链接:https://cn.vjudge.net/problem/URAL-1963 题目大意:给你一个四边形的n个点,让你判断对称点的个数(对称轴的个数*2). 具体思路:感谢qyn的讲解,具体 ...
- 实验吧 smali文件分析
题目链接:http://www.shiyanbar.com/ctf/1871 好吧,这题真是基础中的基础,基础中的战斗机. 不光没有任何绕弯的地方,逻辑有且仅有一个.... 多说无益,使用工具jadx ...
- java.io.IOException: Server returned HTTP response code: 411 for URL
今日调用一post方式提交的http接口,此接口在测试环境ip调用时无问题,但在生产环境通过域名调用时一直报如下错误: java.io.IOException: Server returned HTT ...
- Microsoft SQL - 查询与更新
查询与更新(Query & Update) 转义引号 SQL语句中字符串只能使用单引号,如果需要转义,可用单引号转义单引号. 查询(Inquire) 以下公式中的c指代列名. 规则 1.查询语 ...
- Deep Learning(花书)教材笔记-Math and Machine Learning Basics(线性代数拾遗)
I. Linear Algebra 1. 基础概念回顾 scalar: 标量 vector: 矢量,an array of numbers. matrix: 矩阵, 2-D array of numb ...
- SpringCloud Zuul(路由网关)
⒈Zuul是什么? Zuul包含了两个最主要的功能,对请求的路由和过滤.其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础.过滤器功能则负责对请求的处理过程进行干预,是实 ...
- [Harbor]Docker登录Harbor仓库(HTTP方式)
Docker登录到Harbor仓库时,不管是使用http协议还是使用https协议,都需要修改一些配置. 这篇文章来介绍一下,在使用http协议时,需要进行什么哪些配置. 首先,确定自己的Harbor ...
- 【转】Python模块学习 - fnmatch & glob
[转]Python模块学习 - fnmatch & glob 介绍 fnmatch 和 glob 模块都是用来做字符串匹配文件名的标准库. fnmatch模块 大部分情况下使用字符串匹配查找特 ...
- requests库入门13-会话对象
会话对象可以在跨请求保持某些参数,会话对象有requests api的大部分方法,我理解会话对象就是一个资源共享池 使用requests.Session()可以创建会话对象的实例 还是以之前GitHu ...