简单又复杂的算法--分块

对于区间操作的问题,部分可以用分块来做


事实上分块还是蛮简单的,主要是看分块之后怎么样进行处理,它很灵活,没有固定的模式

还是拿题目来举例吧

Bzoj 2002 Bzoj 3065

Bzoj 2002 分块版
#include"cstdio"
#include"cmath"
#define Maxn 200005
int st[Maxn],pt[Maxn],belong[Maxn],k[Maxn];
int l[1000],r[1000];
inline int read() {
    int x = 0,f = 1;char ch;
    ch = getchar();
    while (ch>'9' || ch<'0') {if (ch == '-') f = -1;ch = getchar();}
    while (ch<='9' && ch>='0') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void init(int n,int block) {
    for (int i = 1;i <= n;i ++) {
        k[i] = read();
        belong[i] = (i-1)/block + 1;
    }
    int cnt;
    if (n%block) cnt = n/block + 1; else
        cnt = n/block;
    for (int i = 1;i <= cnt;i ++) {
        l[i] = (i-1)*block + 1;
        r[i] = i*block;
    }
    r[cnt] = n;
    for (int i = n;i > 0;i --)
        if (i+k[i] > n) st[i] = 1; else
            if (belong[i] == belong[i+k[i]])
                st[i] = st[i+k[i]]+1,pt[i] = pt[i+k[i]]; else
                    st[i] = 1,pt[i] = i+k[i];
}
int cal(int x) {
    int ans = 0;
    while (1) {
        ans += st[x];
        if (!pt[x]) break;
        x = pt[x];
    }
    return ans;
}
int main() {
    int n = read(),block = sqrt(n);
    init(n,block);
    int m = read();
    while (m--) {
        int f = read(),x = read()+1,y;
        if (f == 1) printf("%d\n",cal(x)); else {
            k[x] = y = read();
            for(int i = x;i >= l[belong[x]];i --)
                if (i+k[i] > n) st[i] = 1,pt[i] = 0; else
                    if (belong[i] == belong[i+k[i]])
                        st[i] = st[i+k[i]]+1,pt[i] = pt[i+k[i]]; else
                            st[i] = 1,pt[i] = i+k[i];
        }
    }
    return 0;
}
Bzoj 3065 自己模大佬的分块版
#include"cstdio"
#include"algorithm"
#include"cmath"
using namespace std;
int a[1005][1005],b[1005][1005],inum[100002];
int idx,ipos,tot[1005],nxt[1005];
int cnt,N,B,lastans;
typedef pair<int,int> abcd;
abcd lp,rp;
inline void shuchu() {
    for (int i = 1;i <= cnt;i ++) {
        for (int j = 1;j <= tot[i];j ++)
            printf("%d ",b[i][j]);
        printf("\n");
    }
    printf("\n");
}
inline char read() {
    char ch = getchar();
    while(ch > 'Z' || ch < 'A') ch = getchar();
    return ch;
}
inline abcd kth(int k) {
    for (int i = 1;i;i = nxt[i]) {
        if (!nxt[i] && k>tot[i])
            return abcd(i,k);
        if (k>tot[i])
            k -= tot[i];else
            return abcd(i,k);
    }
}
bool check(int mid,int K) {
    int ret = 0;
    if (lp.first == rp.first) {
        for(int i = lp.second;i <= rp.second;i ++)
            if(a[lp.first][i] <= mid) ret++;
        return ret>=K;
    }
    for(int i = lp.second;i <= tot[lp.first];i ++)
        if (a[lp.first][i] <= mid) ret++;
    for(int i= 1;i <= rp.second;i ++)
        if (a[rp.first][i] <= mid) ret++;
    for (int i = nxt[lp.first];i != rp.first;i = nxt[i])
        ret+=upper_bound(b[i]+1,b[i]+tot[i]+1,mid) - b[i] - 1;
    return ret>=K;
}
void Query() {
    int l,r,K;
    //abcd lp,rp;
    scanf("%d%d%d",&l,&r,&K);
    l^=lastans,r^=lastans,K^=lastans;
    lp = kth(l),rp = kth(r);
    int L=-1,R=70000,MID;
    while (L+1<R)
        if(check(MID = (L+R)>>1,K))
            R = MID; else L = MID;
    //printf("Q %d %d %d\n",l,r,K);
    //shuchu();
    printf("%d\n",lastans = R);

}
void Modify() {
    int x,val,t;
    scanf("%d%d",&x,&val);
    x^=lastans,val^=lastans;
    abcd p = kth(x);
    idx = p.first;
    t = a[idx][p.second];
    ipos = lower_bound(b[idx]+1,b[idx]+tot[idx]+1,t) - b[idx];
    a[idx][p.second] = val;
    b[idx][ipos] = val;
    while (ipos-1>=1 && b[idx][ipos]<b[idx][ipos-1])
        swap(b[idx][ipos],b[idx][ipos-1]),ipos--;
    while (ipos+1<=tot[idx] && b[idx][ipos]>b[idx][ipos+1])
        swap(b[idx][ipos],b[idx][ipos+1]),ipos++;
    //printf("M %d %d\n",x,val);
    //shuchu();
}
void Depth(int idx) {
    cnt ++;
    for (int i = B+1;i <= tot[idx];i ++)
        b[cnt][++tot[cnt]]=a[idx][i],a[cnt][tot[cnt]] = a[idx][i],a[idx][i]=0;
    sort(b[cnt]+1,b[cnt]+tot[cnt]+1);
    tot[idx] -= B;
    for (int i = 1;i <= tot[idx];i ++)
        b[idx][i] = a[idx][i];
    sort(b[idx]+1,b[idx]+tot[idx]+1);
    nxt[cnt] = nxt[idx];nxt[idx] = cnt;
}
void Insert() {
    int x,val;
    scanf("%d%d",&x,&val);
    x^=lastans,val^=lastans;
    abcd p = kth(x);
    idx = p.first;
    for (int i = tot[idx]+1;i>p.second;i --)
        a[idx][i] = a[idx][i-1];
    a[idx][p.second] = val;
    b[idx][++tot[idx]] = val;
    ipos = tot[idx];
    while (ipos-1>=1 && b[idx][ipos]<b[idx][ipos-1])
        swap(b[idx][ipos],b[idx][ipos-1]),ipos--;
    while (ipos+1<=tot[idx] && b[idx][ipos]>b[idx][ipos+1])
        swap(b[idx][ipos],b[idx][ipos+1]),ipos++;
    if (tot[idx]>=2*B) Depth(idx);
    //printf("I %d %d\n",x,val);
    //shuchu();
}
int main() {
    //freopen("t.in","r",stdin);
    int p;
    scanf("%d",&N);
    for (int i = 1;i <= N;i ++) scanf("%d",&inum[i]);
    B = sqrt(N),cnt = (N-1)/B + 1;
    for (int i = 1;i <= N;i ++) {
        idx = (i-1)/B + 1;
        a[idx][++tot[idx]] = inum[i];
        b[idx][tot[idx]] = inum[i];
    }
    for (int i = 1;i <= cnt;i ++)
        sort(b[i]+1,b[i]+tot[i]+1),nxt[i] = i+1;
    nxt[cnt] = 0;
    scanf("%d",&p);
    while (p--) {
        char ch;
        //getchar();
        ch = read();
        if (ch == 'Q')
            Query(); else if (ch == 'M')
                Modify(); else
                    Insert();
    }
    return 0;
}



### YOLOv4-tiny 算法中实现循环分块并分割图像成8块的方法 #### 1. 数据预处理阶段的图像分块策略 为了适应硬件资源有限的情况,在YOLOv4-tiny算法的数据输入阶段,可以通过对原始图片进行切片操作来减少单次送入神经网络的数据量。具体来说,一张完整的待检测图会被切割成为多个子区域[^2]。 对于将整张图片划分为8个小部分这一需求,可以根据实际情况调整裁剪窗口大小和平移步长,确保最终得到恰好八个互不重叠或者有轻微交集(用于提高边缘物体识别精度)的小幅面影像作为后续处理单元。 #### 2. 循环机制的设计思路 考虑到ZCU104平台上的内存局限性,采用循环方式加载这些被划分后的区块有助于进一步优化性能表现。通过设计合理的缓存管理方案,可以在每次迭代过程中只保留当前正在使用的几个批次的数据副本,从而显著削减对外部存储器访问频率的同时也降低了带宽占用率。 当执行一轮完整的前向传播之后,则按照预定顺序切换至下一个未处理过的片段继续上述流程直至全部完成为止;而在反向传播更新权重参数环节同样遵循相同原则依次作用于各个对应的局部特征映射之上。 #### 3. Python代码示例:基于滑动窗技术实现图像分块 下面给出一段简单的Python脚本用来展示如何利用OpenCV库配合NumPy数组索引来达成此目的: ```python import cv2 import numpy as np def split_image_into_blocks(image, block_count=8): height, width = image.shape[:2] # 计算每一块的高度和宽度 h_block_size = int(np.sqrt(block_count) * (height / np.sqrt(block_count))) w_block_size = int(width / np.sqrt(block_count)) blocks = [] y_start = 0 for i in range(int(np.sqrt(block_count))): x_start = 0 for j in range(int(np.sqrt(block_count))): block = image[y_start:y_start+h_block_size, x_start:x_start+w_block_size] blocks.append(block) x_start += w_block_size y_start += h_block_size return blocks if __name__ == "__main__": img_path = "path_to_your_image.jpg" original_img = cv2.imread(img_path) divided_images = split_image_into_blocks(original_img, 8) for idx, div_img in enumerate(divided_images): cv2.imwrite(f'block_{idx}.jpg', div_img) ``` 该函数接受一幅RGB格式彩色照片作为输入,并返回由其分解而成的一系列更小尺寸的新图形列表。这里假设总的分区数目为8,即两行四列布局形式下的产物集合[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值