离线算法和在线算法:
离线算法:在开始时就需要知道问题的所有输入数据,而且在解决一个问题后就要立即输出结果。(例如选择排序)
在线算法:可以以序列化的方式一个个的处理输入,也就是说在开始时并不需要已经知道所有的输入。(例如插入排序)
暴力分块:
可以看一下 洛谷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+