Java教程

Template - 「整体二分」

本文主要是介绍Template - 「整体二分」,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

写的简单。主要是留给自己做复习资料。


Dynamic Rankings.

给定一个含有 \(n\) 个数的序列 \(a_1,a_2 \dots a_n\),需要支持两种操作:

  • Q l r k 表示查询下标在区间 \([l,r]\) 中的第 \(k\) 小的数。
  • C x y 表示将 \(a_x\) 改为 \(y\)。

引入整体二分。

其实就是我们对于二分到的一个值域 mid,去离线针对所有的询问进行 check。

具体是利用一些数据结构。

然后根据 check 和 mid 的大小将询问分为两拨,再分治下去解决问题。

参考于 OI-wiki 的板子很精简且思路便于理解。

#include <cstdio>

int Abs (int x) { return x < 0 ? -x : x; }
int Max (int x, int y) { return x > y ? x : y; }
int Min (int x, int y) { return x < y ? x : y; }

int Read () {
    int x = 0, k = 1;
    char s = getchar();
    while (s < '0' || s > '9') {
        if(s == '-')
            k = -1;
        s = getchar ();
    } 
    while ('0' <= s && s <= '9') 
        x = (x << 3) + (x << 1) + (s ^ 48), s = getchar ();
    return x * k;
}

void Write (int x) {
    if(x < 0) 
        x = -x, putchar ('-');
    if(x > 9)
        Write (x / 10);
    putchar (x % 10 + '0');
}

void Print (int x, char s) { Write (x), putchar (s); }

const int MAXN = 2e5 + 5;

char Opt[3];
int Ans[MAXN], BIT[MAXN], a[MAXN], n, m;

int Low_Bit (int x) {
    return x & -x;
}

void Update (int k, int x) {
    for (int i = k; i <= n; i += Low_Bit (i))
        BIT[i] += x;
}

int Query (int k) {
    int Res = 0;
    for (int i = k; i >= 1; i -= Low_Bit (i))
        Res += BIT[i];
    return Res;
}

struct Node {
    bool Type;
    int Id, x, y, k;
    Node () {}
    Node (bool T, int I, int X, int Y, int K) {
        Type = T, Id = I, x = X, y = Y, k = K;
    }
} q[MAXN], Tmp[2][MAXN];

void Solve (int l, int r, int L, int R) {
    if (l > r || L > R)
        return ;
    if (L == R) {
        for (int i = l; i <= r; i++)
            if (q[i].Type)
                Ans[q[i].Id] = L;
        return ;
    }
    // printf ("%d %d %d %d : //\n", l, r, L, R);
    // for (int i = l; i <= r; i++)
    //     printf ("%d %d %d %d %d\n", q[i].Type, q[i].Id, q[i].x, q[i].y, q[i].k);
    // printf ("//\n");
    int Mid = (L + R) >> 1, Cnt0 = 0, Cnt1 = 0;
    for (int i = l; i <= r; i++) 
        if (q[i].Type) {
            int Check = Query (q[i].y) - Query (q[i].x - 1);
            if (q[i].k <= Check)
                Tmp[0][++Cnt0] = q[i];
            else 
                q[i].k -= Check, Tmp[1][++Cnt1] = q[i];
        }
        else {
            if (q[i].y <= Mid)
                Update (q[i].x, q[i].k), Tmp[0][++Cnt0] = q[i];
            else 
                Tmp[1][++Cnt1] = q[i];
        }
    for (int i = 1; i <= Cnt0; i++)
        if (!Tmp[0][i].Type)
            Update (Tmp[0][i].x, -Tmp[0][i].k);
    for (int i = 1; i <= Cnt0; i++)
        q[l + i - 1] = Tmp[0][i];
    for (int i = 1; i <= Cnt1; i++)
        q[l + Cnt0 + i - 1] = Tmp[1][i];
    Solve (l, l + Cnt0 - 1, L, Mid), Solve (l + Cnt0, r, Mid + 1, R);
}

int main () {
    n = Read (), m = Read ();
    int p = 0, Tot = 0;
    for (int i = 1, x; i <= n; i++)
        x = Read (), q[++p] = Node (0, 0, i, x, 1), a[i] = x;
    for (int i = 1, x, y; i <= m; i++) {
        scanf ("%s", Opt + 1), x = Read (), y = Read ();
        if (Opt[1] == 'Q') {
            int k = Read ();
            q[++p] = Node (1, ++Tot, x, y, k);
        }
        else 
            q[++p] = Node (0, 0, x, a[x], -1), q[++p] = Node (0, 0, x, y, 1), a[x] = y;
    }
    Solve (1, p, 0, 1e9);
    for (int i = 1; i <= Tot; i++)
        Print (Ans[i], '\n');
    return 0;
}
这篇关于Template - 「整体二分」的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!