• 莫队算法


    转自 http://vawait.com/manhattanmst/

    严谨的论文请看:戳这里或者戳这里,还有一个blog的也可以看看:戳这里

    可以证明每一个顶点在最小生成树中在这45度的范围内至多仅有一条边与之相连,也就是如果以一个点为原点,那么上面分成的八个区域里面最多和每个区域连一条边。

    首先只考虑R1区间的。把每个坐标都按x为第一关键字,y为第二关键字排序。从后往前处理,那么能保证处理到第i个点时,比Xi大的点都已经处理过了。也就是以第i点为原点时,其他点只在R1,、R2、R3、R4区间。现在找R1区间的点,通过位移使得i点在原点,那么R1区间的点必然满足Xj<Yj,因为i点为原点,所以在原坐标中满足Xj-Xi<Yj-Yi,转移一下得Yj-Xj>Yi-Xi。也就是在Xj>Xi并且满足Yj-Xj>Yi-Xi中找一个离i点最近的点。因为Xi<Xj,Yi<Yj,所以曼哈顿距离为(Xj+Yj)-(Xi+Yi),后面的为常数,只考虑前面的即可。

    总的算法是先排序,按x为第一关键字,y为第二关键字。然后以每个点的Yi-Xi的值得出排名F[i]。按排序的顺序倒序处理i点,每次找F[j]比F[i]大的并且是Xj+Yj最小的点连边。这个可以以F[i]作为标号,Xi+Yi作为值,用线段树或者树状数组维护即可。

    考虑到对称性所以只需要处理4个区域,每个区域可以通过对称转移到R1,所以循环四次每次只是处理坐标,算法还是一样。

    这就是莫队算法了,如果知道区间[l,r]的信息,可以O(1)得到[l+1,r]的信息,那么其转移复杂度就相当于曼哈顿距离。可以找出曼哈顿最小生成树然后按照连边处理信息。

    最后是我的代码,只有莫队算法处理边还没有求最小生成树的:

    const int maxn = 100010;
    int n , t , x , f[maxn] , c[maxn];
     
    struct bit
    {
        int t[100100] , n;
        void cl() { clr( t, 0 ); }
        void add(int x,int y) {
            for ( ; x; x -= x & (-x) ) if( c[y] < c[t[x]] ) t[x] = y;
        }
        int ask(int x) {
            int s = 0;
            for ( ; x <= 100000; x += x & (-x) ) if ( c[s] > c[t[x]] ) s = t[x];
            return s;
        }
    } T;
     
    struct nodd
    {
        int x , y , n;
    } a[maxn] , d[maxn] , b[4*maxn];
     
    bool cmp(nodd a,nodd b) { return a.x == b.x ? a.y < b.y : a.x < b.x; }
     
    void add(int x,int y,int d)
    {
        b[++t].x = x; b[t].y = y;
        b[t].n = d;
    }
     
    void init()
    {
        rep(i,1,n) scanf("%d%d",&a[i].x,&a[i].y) , a[i].n = i;
        t = 0;
        rep(k,1,4) {
            if ( k == 2 || k == 4 ) rep(i,1,n) swap(a[i].x,a[i].y);
            if ( k == 3 ) rep(i,1,n) a[i].x = -a[i].x;
            sort( a + 1 , a + 1 + n , cmp );
            rep(i,1,n) d[i].x = a[i].y - a[i].x , d[i].y = i;
            rep(i,1,n) c[i] = a[i].x + a[i].y;
            c[0] = 2000000000;
            sort( d + 1 , d + 1 + n , cmp );
            rep(i,1,n) f[d[i].y] = i;
            T.cl();
            red(i,n,1) {
                if ( x = T.ask(f[i]) ) add( a[i].n , a[x].n , c[x] - c[i] );;
                T.add(f[i],i);
            }
        }
    }
    View Code
  • 相关阅读:
    OpenStack-Ocata版+CentOS7.6 云平台环境搭建 — 2.安装配置OpenStack基础服务
    OpenStack-Ocata版+CentOS7.6 云平台环境搭建 — 1.操作系统环境配置
    ssh免密登录
    PHP实现识别带emoji表情的字符串
    算法-PHP实现八大算法
    项目总结-第一次外包项目2-项目相关
    PHP.52-TP框架商城应用实例-前台4-商品详情页-面包屑导航、AJAX浏览历史
    PHP.51-TP框架商城应用实例-前台3-楼层推荐、TP框架雪崩问题
    PHP.50-TP框架商城应用实例-前台2-商品推荐
    PHP.49-TP框架商城应用实例-前台1-公共布局、制作首页
  • 原文地址:https://www.cnblogs.com/Opaser/p/4454335.html
Copyright © 2020-2023  润新知