Load Balancing solution report (USACO 2016 February Contest, Silver. Problem 2. sorting tree array discretization)

USACO (W) (funny)

Topic analysis

Topic online details (submitted address): Http://www.usaco.org/index.php? Page=viewproblem2&cpid=619

The meaning of the topic is very simple. Given a two-dimensional matrix (farm), there are many points (cattle) placed in it, so that we can cut the horizontal and vertical two knives in a suitable place, so that the points in the four regions with the middle point are the least. (what, not yet understood? Go back to the subject details and continue to bite English.

Algorithm design

Without considering the special advanced algorithm of k-d tree, let's first think about how to do violence. Enumerate each cutting point (the intersection point of horizontal vertical cut line). However, we can find that because X and y are very large, the final time of the program will be very slow.

Wait! Why are they more than 1000? Yes, we can simply think in the brain, such a large matrix, a lot of space is 0, that is, we enumerated a lot of useless location points, we can x, y alone (think why do it alone can be done) to make a discretization, so that the scope of enumeration can be reduced quickly. A step closer to success!

However, it is still very slow O (n^3), the reason is actually very simple, because the points in the statistical area are very slow, every statistic we have counted the last statistics. Then why don't we think of a way to solve this problem? First of all, we can make these cows. order (actually, this is my initial idea, earlier than the discretization idea). We pushed forward according to the line, then we set up a tree array on the upper and lower level of the horizontal cutting line. Actually, at first, my idea was to set up a line tree for every line, but found that there was no need to build one on every line. Then enumerated each vertical cut line, so that our complexity reduced to O (n ^ 2 * logn).

Example code


const int N = 1100;

int n;
struct cd {
    int x, y;
} c[N];

bool cmp(cd a, cd b) {
    if (a.x == b.x) return a.y < b.y;
    return a.x < b.x;

int *d[N];

bool cmp_d(int *a, int *b) {
    return *a < *b;

int t[N], b[N]; // 水平轴切开的上下两部分,top bottom 

void change(int t[], int k, int x) {
    while (k <= n) {
        t[k] += x;
        k += k & (-k); 

int sum(int t[], int k) {
    int x = 0;
    while (k > 0) {
        x += t[k];
        k -= k & (-k);
    return x;

int main() {
//  freopen("input.txt", "r", stdin);
    freopen("balancing.in", "r", stdin);
    freopen("balancing.out", "w", stdout);

    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d%d", &c[i].x, &c[i].y);

    // 对x进行排序,便于下方移动水平轴 
    std::sort(c + 1, c + n + 1, cmp); 
//  for (int i = 1; i <= n; i++) printf("%d %d\n", c[i].x, c[i].y); printf("\n");

    // 对y进行离散化,便于下方移 动垂直轴
    for (int i = 1; i <= n; i++) d[i] = &c[i].y;
    std::sort(d + 1, d + n + 1, cmp_d); 
    int last = 0, count = 0;
    for (int i = 1; i <= n; i++) {
        if (*d[i] != last) {
            last = *d[i];
        *d[i] = count;
//  for (int i = 1; i <= n; i++) printf("%d %d\n", c[i].x, c[i].y); printf("\n");

    // 移动水平轴,并且枚举垂直轴 
    memset(t, 0, sizeof t);
    memset(b, 0, sizeof b);
    for (int i = 1; i <= n; i++) change(b, c[i].y, 1); // 先填充水平轴下方的内容
    int ans = 0x7fffffff;
    int i = 1;
    while (i <= n) {
        int row = c[i].x; 
        // 从水平轴下方删除,并且添加到水平轴上方
        while (i <= n && c[i].x == row) {
            change(t, c[i].y, 1);
            change(b, c[i].y, -1);

        for (int j = 1; j <= n; j++) { 
            int tmp, stage_ans = 0;
            tmp = sum(t, j); // 上左 
            if (tmp > stage_ans) stage_ans = tmp; 
tmp = sum (T, n) - TMP; / / upper right 
if (TMP > stage_ans) stage_ans = TMP; 
tmp = stage_ans; (/) (/ / lower left ((>)) = =;; = = (()); - / / lower right ((>)) = =;; ((<)) = =; (0);