分块思想

----------------------------------------------------------

线性分块, 国外通常把块大小为 sqrt(n) 的分块方式叫做 “SQRT Decomposition”。

资料:

《入门经典:训练指南》P395

http://sysmagazine.com/posts/138946/

http://algoacm.com/Algorithms/sqrt_decomposition/sqrt_decomposition.html


题目:

Uva 12003 Array Transformer

#include<bits/stdc++.h>
using namespace std;

#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))

typedef long long LL;

struct Edge{
    int u, v, c;
    Edge(){}
    Edge(int u, int v, int c):u(u), v(v), c(c){}
    int getAdj(int x) {
        return x == u ? v : u;
    }
};

const int Maxn = 300000;
const int SIZE = 4096;
int n, m, u, a[Maxn+5], block[Maxn/SIZE+5][SIZE], numBlock, numLastBlock;
//#define DEBUG
void init() {
    cin >> n >> m >> u;
    int b = 0, j = 0;
    rep(i, 0, n-1) {
        cin >> a[i];
        block[b][j] = a[i];
        ++j;
        if (j == SIZE) {++b;j=0;}
    }
    rep(i, 0, b-1) sort(block[i], block[i]+SIZE);
    if (j) sort(block[b], block[b]+j);
    numBlock = b;
    numLastBlock = j ? j : SIZE;
}

int countOrderedRange(const int * l, const int * r, int v) {
    int ret = 0;
    for (const int *p=l;p<=r;++p) {
        if (*p < v) ++ret;
    }
    return ret;
}

int Query(int L, int R, int v) {
    int lb = L/SIZE, rb = R/SIZE, ret = 0;
    rep(i, lb+1, rb-1) {
        ret += lower_bound(block[i], block[i]+SIZE, v) - block[i];
    }
    if (lb == rb) {
        ret += countOrderedRange(a+L, a+R, v);
    }
    else {
        ret += countOrderedRange(a+L, a+(lb+1)*SIZE-1, v);
        ret += countOrderedRange(a+rb*SIZE, a+R, v);
    }
    return ret;
}

void Update(int p, int x) {
    int * B = block[p/SIZE];
    int old = a[p];
    a[p] = x;

    const int bSize = p/SIZE == numBlock ? numLastBlock : SIZE;
    int pos = lower_bound(B, B+bSize, old) - B;
#ifdef DEBUG
    cout << "in update: old->" << old  << " pos->" << pos << endl;
    cout << "Elements in this block: ";
    rep(i, 0, bSize-2) cout << B[i] << ' ';cout << B[bSize-1] << endl;
#endif
    while (pos > 0 && x < B[pos-1]) {
            B[pos] = B[pos-1];
            --pos;
    }
    while (pos < bSize-1 && x > B[pos+1]) {
        B[pos] = B[pos+1];
        ++pos;
    }
    B[pos] = x;
}

void printBlocks() {
    cout << "-------Show Blocks-------" << endl;
    rep(i, 0, numBlock-1) {
        cout << "Block " << i << ": ";
        rep(j, 0, SIZE-2) cout << block[i][j] << ' ';cout << block[i][SIZE-1] << endl;
    }
    cout << "Block " << numBlock << ": ";
    rep(j, 0, numLastBlock-2) cout << block[numBlock][j] << ' ';cout << block[numBlock][numLastBlock-1] << endl;
}


int main() {
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
#endif
    SPEED_UP
    init();

    //printBlocks();

    while (m--) {
        int L, R, v, p;
        cin >> L >> R >> v >> p;
        --L;--R;--p;

        int k = Query(L, R, v);
        Update(p, u*1ll*k/(R-L+1));
#ifdef DEBUG
        cout << "Q: " << L << ' ' << R << ' ' << v << ' ' << p << " k: " << k << endl;
        printBlocks();
#endif
    }

    rep(i, 0, n-1) cout << a[i] << endl;

    return 0;
}

hdu 5057 Argestes and Sequence

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <limits>
#include <set>
#include <map>
using namespace std;

#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))

typedef long long LL;

#define Maxn 100000
#define SIZE 256
const int numBlocks = Maxn/SIZE+1;
int pow10[11];
int a[Maxn+5], b[numBlocks+5][11][10], szLastBlock, n, m;

void clear(int n) {
    rep(i, 0, n/SIZE+1) rep(j, 0, 10) rep(k, 0, 9) b[i][j][k] = 0;
}

void init() {
    scanf("%d%d", &n, &m);
    clear(n);
    rep(i, 0, n-1) {
        scanf("%d", a+i);
        int t = a[i];
        rep(j, 1, 10) {
            b[i/SIZE][j][t%10] += 1;
            t /= 10;
        }
    }
    szLastBlock = n%SIZE;
    if (!szLastBlock)
        szLastBlock = SIZE;
}

void Update(int p, int x) {
    int old = a[p], idx = p/SIZE;
    a[p] = x;
    rep(i, 1, 10) {
        b[idx][i][old%10] -= 1;
        b[idx][i][x%10]   += 1;
        old /= 10;
        x /= 10;
    }
}

int countRange(int L, int R, int D, int P) {
    int ret = 0;
    rep(i, L, R) {
        int t = a[i]/pow10[D-1]%10;
        if (t == P) ++ret;
    }
    return ret;
}

int Query(int idx, int D, int P) {
    int r = idx/SIZE, ret = 0;
    rep(i, 0, r-1) ret += b[i][D][P];
    ret += countRange(r*SIZE, idx, D, P);
    return ret;
}

void printBlocks() {
    cout << "-------Show Blocks-------" << endl;
    rep(i, 0, numBlocks-1) {
        cout << "Block " << i << ": " << endl;;
        rep(d, 1, 10)
            rep(j, 0, 9){
            cout << "digit " << d << "=" << j << ": " << b[i][d][j] << endl;
        }
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
#endif
    //SPEED_UP
    pow10[0] = 1;
    rep(i, 1, 10) pow10[i] = pow10[i-1]*10;
    int T;
    scanf("%d", &T);
    char ch;
    int aa, bb, cc, dd;
    while (T--) {
        init();
        rep(i, 1, m) {
            getchar();
            scanf("%c", &ch);
            if (ch == 'Q') {
                scanf("%d%d%d%d", &aa, &bb, &cc, &dd);
                printf("%d\n", Query(bb-1, cc, dd)-Query(aa-2, cc, dd));
            }
            else {
                scanf("%d%d", &aa, &bb);
                Update(aa-1, bb);
            }
        }
    }

    return 0;
}


codeforces 13E - Holes

//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <limits>
#include <set>
#include <map>
using namespace std;

#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))

typedef long long LL;

#define Maxn 100000
#define SIZE 256
const int numBlocks = Maxn/SIZE+1;

// 每个分块保存其左右端点
struct node{
    int l, r;
};
node b[numBlocks+5];
int power[Maxn+5], nxt[Maxn+5], cnt[Maxn+5], n, m;

void update(int i) {
    int idx = i + power[i], iBlock = i/SIZE;
    if (idx >= n) {
        nxt[i] = idx;
        cnt[i] = 1;
    }
    else if (idx/SIZE == iBlock) {
        nxt[i] = nxt[idx];
        cnt[i] = cnt[idx]+1;
    }
    else {
        nxt[i] = idx;
        cnt[i] = 1;
    }
}

void init() {
    scanf("%d%d", &n,&m);
    rep(i, 0, n-1) scanf("%d", power+i);
    rep(i, 0, n/SIZE) {
        b[i].l = i*SIZE;
        b[i].r = (i+1)*SIZE-1;
    }
    b[n/SIZE].r = n-1;

    urep(i, n-1, 0) update(i);
}

int jump_in_block(int x) {
    int iBlock = x/SIZE, idx = x;
    while (idx + power[idx] < n) idx = idx + power[idx];
    return idx;
}

void Update(int p, int x) {
    power[p] = x;
    int iBlock = p/SIZE;
    // 每当更新一个位置,要将同一分块中且在其前的位置全部更新
    urep(i, p, b[iBlock].l) update(i);
}

void Jump(int x) {
    int idx = x, c  = 0, old, last;
    //cout << "---- test " << x << " ----\n";
    while (idx < n) {
        old = idx;
        c += cnt[idx];
        if (nxt[idx] >= n) {
            last = jump_in_block(idx);
        }
        idx = nxt[idx];
        //if (idx < n)
        //    cout << "from " << old << " jump to " << idx << " with " << cnt[old] << " jumps\n";
    }
    //cout << "last visit: " << last << " jumps: " << c << endl;
    //cout << last+1 << ' ' << c << endl;
    printf("%d %d\n", last+1, c);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
#endif
    //SPEED_UP
    init();

    int op, aa, bb;
    rep(i, 1, m) {
        //cin >> op;
        scanf("%d", &op);
        if (!op) {
            //cin >> aa >> bb;
            scanf("%d%d", &aa, &bb);
            Update(aa-1, bb);
        }
        else {
            //cin >> aa;
            scanf("%d", &aa);
            Jump(aa-1);
        }
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值