浏览器标题切换
浏览器标题切换end

寒假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+

 

 

 

 

posted @ 2020-01-11 23:21  抓水母的派大星  阅读(148)  评论(0编辑  收藏  举报