题意:有n个炸弹和水果,一个长为w高为h的木板,然后给出每个炸弹或水果的坐标,问木板一次能拍到最多多少个水果且不包含炸弹,四个边界都记入统计,先输出方案数(如果是四个边界都有水果的情况,方案数加一,否则输出so many),然后输出个数。
题解:不知道怎么判断四个边界上是否有水果,看了 的做法,把每个水果和炸弹x坐标乘2,那么如果最大值出现在x坐标为奇数,说明一定两个竖直边界没有水果或炸弹也就是so many。因为四个边界都计入,所以先处理下边界再处理上边界,这和Poj 2482相反。可以一次处理所有在同一y坐标的所有扫描线,先处理全部下边界更新最大值,然后再处理全部上边界,此时的最大值如果不变或变大说明上边界没有水果或有炸弹也就是so many。线段树维护区间内水果数量的最大值和当前被覆盖的区间的方案数总和。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#define ll long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 100005;
struct Line {
    int lx, rx, h;
    int flag, v;
    Line(int a, int b, int c, int d, int e): lx(a), rx(b), h(c), flag(d), v(e) {}
    bool operator < (const Line& a) const { return h < a.h || (h == a.h && flag > a.flag); }
};
int n, h, w;
ll flag[N << 2], tree[N << 2], num[N << 2];
vector<Line> line;

void pushup(int k) {
    tree[k] = max(tree[k * 2], tree[k * 2 + 1]);
    num[k] = 0;
    if (tree[k] == tree[k * 2])
        num[k] += num[k * 2];
    if (tree[k] == tree[k * 2 + 1])
        num[k] += num[k * 2 + 1];
}

void pushdown(int k) {
    if (flag[k]) {
        flag[k * 2] += flag[k];
        flag[k * 2 + 1] += flag[k];
        tree[k * 2] += flag[k];
        tree[k * 2 + 1] += flag[k];
        flag[k] = 0;
    }
}

void build(int k, int left, int right) {
    tree[k] = flag[k] = 0;
    num[k] = INF;
    if (left == right) {
        if ((left % 2) == 0)
            num[k] = 1;
        return;
    }
    int mid = (left + right) / 2;
    build(k * 2, left, mid);
    build(k * 2 + 1, mid + 1, right);
}

void modify(int k, int left, int right, int l, int r, int v) {
    if (l <= left && right <= r) {
        flag[k] += (ll)v;
        tree[k] += (ll)v;
        return;
    }
    pushdown(k);
    int mid = (left + right) / 2;
    if (l <= mid)
        modify(k * 2, left, mid, l, r, v);
    if (r > mid)
        modify(k * 2 + 1, mid + 1, right, l, r, v);
    pushup(k);
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        line.clear();
        scanf("%d%d%d", &n, &h, &w);
        char kind[5];
        int x, y, minn = INF, maxx = -INF;
        for (int i = 0; i < n; i++) {
            scanf("%s%d%d", kind, &x, &y);
            if (kind[0] == 'B') {
                line.push_back(Line(x * 2, (x + w) * 2, y, 1, -INF));
                line.push_back(Line(x * 2, (x + w) * 2, y + h, -1, INF));
            }
            else {
                line.push_back(Line(x * 2, (x + w) * 2, y, 1, 1));
                line.push_back(Line(x * 2, (x + w) * 2, y + h, -1, -1));
            }
            minn = min(minn, x * 2);
            maxx = max(maxx, (x + w) * 2);
        }
        sort(line.begin(), line.end());
        build(1, minn, maxx);
        int sz = line.size();
        ll res = 0, cnt = 0;
        for (int i = 0; i < sz;) {
            int cur = line[i].h;
            while (i < sz && line[i].h == cur && line[i].flag == 1) {
                modify(1, minn, maxx, line[i].lx, line[i].rx, line[i].v);
                i++;
            }
            if (res < tree[1]) {
                res = tree[1];
                cnt = num[1];
            } else if (res == tree[1])
                cnt += num[1];
            while (i < sz && line[i].h == cur && line[i].flag == -1) {
                modify(1, minn, maxx, line[i].lx, line[i].rx, line[i].v);
                i++;
            }
            if (res <= tree[1]) {
                res = tree[1];
                cnt = INF;
            }
        }
        if (cnt < INF) printf("%lld\n", cnt);
        else printf("so many!\n");
        printf("%lld\n\n", res);
    }
    return 0;
}