点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。

      下面我们分情况讨论:

        1. x1>x2且y1>y2。这与|AB|≤|AC|矛盾;
        2. 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|;
        3. x1>x2且y1≤y2。与2同理;
        4. 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最小生成树的莫队算法的更多相关文章

  1. BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7687  Solved: 3516[Subm ...

  2. bzoj 2038 莫队算法

    莫队算法,具体的可以看10年莫涛的论文. 大题思路就是假设对于区间l,r我们有了一个答案,那么对于区间l,r+1,我们 可以暴力的转移一个答案,那么对于区间l1,r1和区间l2,r2,需要暴力处理 的 ...

  3. HYSBZ2038 小Z的袜子(莫队算法)

    今天学了一下传说中的解决离线询问不修改的一种算法.题目的意思非常简单,就是询问在一个[L,R]区间里的取两个物品,然后这两个物品颜色相同的概率.其实就是对于每种颜色i,这个区间里对应的个数cnt[i] ...

  4. bzoj 3809 Gty的二逼妹子序列(莫队算法,块状链表)

    [题意] 回答若干个询问,(l,r,a,b):区间[l,r]内权值在[a,b]的数有多少[种]. [思路] 考虑使用块状链表实现莫队算法中的插入与删除. 因为权值处于1..n之间,所以我们可以建一个基 ...

  5. BZOJ 3236 AHOI 2013 作业 莫队算法

    题目大意:给出一些数,问在一个区间中不同的数值有多少种,和在一个区间中不同的数值有多少个. 思路:因为没有改动,所以就想到了莫队算法.然后我写了5K+的曼哈顿距离最小生成树,然后果断T了.(100s的 ...

  6. XOR and Favorite Number(莫队算法+分块)

    E. XOR and Favorite Number time limit per test 4 seconds memory limit per test 256 megabytes input s ...

  7. BZOJ 2038: [2009国家集训队]小Z的袜子(hose)【莫队算法裸题&&学习笔记】

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 9894  Solved: 4561[Subm ...

  8. 【国家集训队2010】小Z的袜子[莫队算法]

    [莫队算法][国家集训队2010]小Z的袜子 Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程, ...

  9. 莫队算法详解和c实现

    解析和实现 摘要:        莫队算法是一个对于区间.树或其他结构离线(在线)维护的算法,此算法基于一些基本算法,例如暴力维护,树状数组,分块,最小曼哈顿距离生成树,对其进行揉合从而产生的一个简单 ...

随机推荐

  1. shiro-5基于url的权限管理

    1.1 搭建环境 1.1.1 数据库 mysql5.1数据库中创建表:用户表.角色表.权限表(实质上是权限和资源的结合 ).用户角色表.角色权限表. 完成权限管理的数据模型创建. 1.1.2 开发环境 ...

  2. gulp3 和 gulp4 区别

    运行gulp项目报错:AssertionError: Task function must be specified 今天像往常一样,编写文章,并使用gulp bulid压缩代码,但是一运行:gulp ...

  3. Solr创建Core的两种方法

    创建Core的两种方法: 第一种方法: 1.打开dos命令窗口,切换目录到${solr.home}\bin,然后输入:solr create -c corename之后回车: 2.打开solr安装文件 ...

  4. WPF DataGrid中鼠标双击某一列,弹出窗体作为(增加、修改、详细)按钮的快捷键。

    跟触发器行为有关,什么是触发器什么是行为,百度其他人写的乱七八糟的,我并不能看懂.在此先强行记忆,后知后觉,再回来理解. <i:Interaction.Triggers> <i:Ev ...

  5. 围在栅栏中的爱WriteUp(附QWE密码加解密脚本)

    题目的链接:http://www.shiyanbar.com/ctf/1917 1.首先题目给出的是摩尔斯电码: 在下面的网站上解密:https://www.cryptool.org/en/cto-c ...

  6. NOIP2018D1T1 铺设道路

    原题:NOIP2013D1T1 积木大赛 题目地址:P5019 铺设道路 思路:玄学瞎搞 将每块区域插入一个小根堆,这里的小根堆用优先队列实现,即运用一个 \(pair\) , \(first\) 为 ...

  7. 为什么要重写equals和hashcode方法

    equals hashcode  当新建一个java类时,需要重写equals和hashcode方法,大家都知道!但是,为什么要重写呢? 需要保证对象调用equals方法为true时,hashcode ...

  8. canvas贪吃蛇游戏

    用canvas做了一个贪吃蛇小游戏 开始界面 游戏界面 结束界面 <!DOCTYPE html>  <html>  <head>  <meta charset ...

  9. 709. To Lower Case

    Algorithm to-lower-case https://leetcode.com/problems/to-lower-case/ 1)problem Implement function To ...

  10. 红迅JSAAS敏捷开发平台

    红迅JSAAS敏捷开发平台:    http://www.redxun.cn/