zoukankan      html  css  js  c++  java
  • 【算法】分块——教主的魔法&不勤劳的图书管理员

    由不勤劳的图书管理员带入了分块的坑,深深地被其暴力与优雅所征服。分块的实质就是将暴力块状封装起来,一整块的部分就一整块处理,零碎的部分就怎么暴力怎么来。因为分块大小的原因,限制了零碎部分数据的数量级,所以复杂度得以保证。

    1.教主的魔法:可以算得上是一个分块的板子题。对于每一个块内sort排序,保存id值。对于修改,块内的找到点暴力修改之后重新排序,一整个块的不改变相对大小关系,所以直接外部记录累加的值。查询也一样,块外暴力,块内二分查找。

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    #define maxn 2000000
    #define maxb 1050
    int n, q, B, sum[maxb], a[maxn], cnt[maxb];
    struct node
    {
        int v, id;
    }c[maxb][maxb];
    
    int read()
    {
        int x = 0;
        char c;
        c = getchar();
        while(c < '0' || c > '9') c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x;
    }
    
    bool cmp(node a, node b)
    {
        return a. v < b.v;
    }
    
    void Vio_C(int b, int x, int w)
    {
        c[b][x].v += w;
    }
    
    void Change(int L, int R, int W)
    {
        int a = L / B, b = R / B;
        if(a == b)
        {
            for(int i = 1; i <= cnt[a]; i ++) 
                if(c[a][i].id >= L && c[a][i].id <= R) Vio_C(a, i, W);
                sort(c[a] + 1, c[a] + cnt[a] + 1, cmp);
         return 0; }
    for(int i = 1; i <= cnt[a]; i ++) if(c[a][i].id >= L) Vio_C(a, i, W); sort(c[a] + 1, c[a] + cnt[a] + 1, cmp); for(int i = 1; i <= cnt[b]; i ++) if(c[b][i].id <= R) Vio_C(b, i, W); sort(c[b] + 1, c[b] + cnt[b] + 1, cmp); for(int i = a + 1; i < b; i ++) sum[i] += W; } int check(int b, int C) { C -= sum[b]; int ans = cnt[b] + 1, l = 1, r = cnt[b]; while(l <= r) { int mid = (l + r) >> 1; if(c[b][mid].v >= C) ans = mid, r = mid - 1; else l = mid + 1; } return cnt[b] - ans + 1; } void Query(int L, int R, int C) { int a = L / B, b = R / B; int ans = 0; if(a == b) { C -= sum[a]; for(int i = 1; i <= cnt[a]; i ++) if(c[a][i].id >= L && c[a][i].id <= R && c[a][i].v >= C) ans ++; printf("%lld ", ans); return; } for(int i = 1; i <= cnt[a]; i ++) if(c[a][i].id >= L && c[a][i].v + sum[a] >= C) ans ++; for(int i = 1; i <= cnt[b]; i ++) if(c[b][i].id <= R && c[b][i].v + sum[b] >= C) ans ++; for(int i = a + 1; i < b; i ++) ans += check(i, C); printf("%lld ", ans); return; } signed main() { n = read(), q = read(); B = sqrt(n); for(int i = 1; i <= n; i ++) { a[i] = read(); int block = i / B; c[block][++ cnt[block]].v = a[i]; c[block][cnt[block]].id = i; if(((i / B) != (i + 1) / B) || i == n) sort(c[block] + 1, c[block] + cnt[block] + 1, cmp); } for(int i = 1; i <= q; i ++) { char c; cin >> c; int L = read(), R = read(), W = read(); if(c == 'M') Change(L, R, W); else Query(L, R, W); } return 0; }

    2.不勤劳的图书管理员

    这题首先注意到交换a,b的位置,只会影响到a,b之间的数。在一段区间里,a对杂乱值的贡献是多少?不难发现=在a之前且应当在a之后的书本杂乱值之和+v[a]*前面书本的个数。所以我们对每一个块使用两个树状数组,一个纪录个数,一个记录页数的前缀和,块内的利用树状数组快速查询,块外的暴力枚举计算即可。

    因为此题代码是Kuai的(那个时候还不会写分块),所以就不贴代码啦。

  • 相关阅读:
    HDU4474 Yet Another Multiple Problem BFS搜索
    HDU4473 Exam 数学分析
    2013ACM多校联合(4)
    POJ1273 网络流...
    HDU4472 Count 递推
    POJ1149 PIGS 网络流
    UVA10881 Piotr's Ants 想法题
    javascript js string.Format()收集
    修改 设置 vs.net 网站 调试 设为 起始页
    【转】HTML5杂谈 概念与现行游戏 割绳子 宝石迷阵
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8487856.html
Copyright © 2011-2022 走看看