• 寒假Day1:莫队算法+暴力分块


    离线算法和在线算法:

    离线算法:在开始时就需要知道问题的所有输入数据,而且在解决一个问题后就要立即输出结果。(例如选择排序)

    在线算法:可以以序列化的方式一个个的处理输入,也就是说在开始时并不需要已经知道所有的输入。(例如插入排序)

    暴力分块:

    可以看一下 洛谷P1816 忠诚    https://www.luogu.com.cn/problem/P1816

    题解:https://www.luogu.com.cn/problemnew/solution/P1816?page=2 

    查询给定区间内的最小值。

     

    分块就是把一个待求的序列分成√N块之后暴力查找,把查找分成整块和散块两种。

    预处理每块内最小值与每个数在哪个块,这样方便O(1)查询。

    先看一下暴力分块的相关知识再去看莫队

    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #include<cmath>
    #include<iostream>
    using namespace std;
    #define inf 0x3f3f3f3f
    const int N=1e5+20;
    
    int block;
    int a[N],belong[N],minn[N];
    
    int query(int x,int y)
    {
        int m=inf;
        for(int i=x;i<=min(belong[x]*block,y);i++)
            m=min(a[i],m);
        if(belong[x]!=belong[y])
        {
            for(int i=(belong[y]-1)*block+1;i<=y;i++)
                m=min(m,a[i]);
        }
        for(int i=belong[x]+1;i<=belong[y]-1;i++)
            m=min(m,minn[i]);
        return m;
    }
    
    int main()
    {
        int n,k,aa,bb;
        scanf("%d %d",&n,&k);
        block=sqrt(n);
        memset(minn,inf,sizeof(minn));//注意清inf
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            belong[i]=(i-1)/block+1;
            minn[belong[i]]=min(minn[belong[i]],a[i]);
            //minn中记录的最小值是相对于每一块而言的,不是每一个下标
            //用每一块的最小值和当前值进行比较取最小值
        }
    
        for(int i=1;i<=k;i++)
        {
            scanf("%d %d",&aa,&bb);
            int w=query(aa,bb);
            if(i==k)
                printf("%d\n",w);
            else
                printf("%d ",w);
        }
        return 0;
    }

     

     

    莫队算法:

    欧式距离:就是勾股定理

    曼哈顿距离:

    切比雪夫距离:

    • 处理的问题:不带区间修改的区间查询问题,是离线问题。(有些题目当前这一问要异或上一问的答案,就算是强制在线)
    • 时间复杂度:n√n  常数大一点就不行
    • 已知 [ L,R ] ,就可以在 O(1) 的时间复杂度求出 [ L-1,R ] 、[ L+1,R ] 、[ L,R-1 ] 、[ L,R+1 ] 的答案。所以计算[L',R']的答案花的时间为|L-L'|+|R-R'|。如果把询问[L,R]看做平面上的点a(L,R).询问[L',R']看做点b(L',R')的话。那么时间开销就为两点的曼哈顿距离。所以对于每个询问看做一个点。我们要按一定顺序计算每个值。那开销就为曼哈顿距离的和。要计算到每个点。那么路径至少是一棵树。所以问题就变成了求二维平面的最小曼哈顿距离生成树。

    小知识点

    • 在函数调用中,传入的参数是x和&x是不一样的,传入x也就是在调用函数中改变x的值,原函数不变;传入&x,也就是传入地址,原函数会改变
    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<iostream>
    using namespace std;
    #define inf 0x3f3f3f3f
    
    void cmp1(int x)
    {
        x+=10;
    }
    
    void cmp2(int &x)
    {
        x+=10;
    }
    
    int main()
    {
        int a=1,b=1;
        cmp1(a);
        cmp2(b);
        printf("a=%d\n",a); // -> a=1
        printf("b=%d\n",b); // -> b=11
        return 0;
    }

    凡事不懂得的一定要自己上机操作,并且记录问题所在,一定要自己动手!!!

    TO DO LIST:

    • 暴力分块
    • 莫队算法
    • W 50+

     

  • 相关阅读:
    h5唤起app
    app唤起的完美解决方案,及阻止浏览器的默认弹窗行为
    cdn
    函数声明和函数表达式的区别
    基础系列(7)—— 结构
    基础系列(4)—— C#装箱和拆箱
    重温软件工程——对软件工程的初步了解
    基础系列(9)—— 抽象方法和接口
    自学系列--git的基础简介
    设计模式之简单工厂模式
  • 原文地址:https://www.cnblogs.com/OFSHK/p/12181516.html
Copyright © 2020-2023  润新知