AtCoder Beginner Contest 176 E - Bomber

Problem Statement
We have a two-dimensional grid with H × W H×W H×W squares. There are M M M targets to destroy in this grid - the position of the i i i-th target is ( h i , w i ) (h_i,w_i) (hi,wi).

Takahashi will choose one square in this grid, place a bomb there, and ignite it. The bomb will destroy all targets that are in the row or the column where the bomb is placed. It is possible to place the bomb at a square with a target.

Takahashi is trying to maximize the number of targets to destroy. Find the maximum number of targets that can be destroyed.

Constraints

  • All values in input are integers.
  • 1 ≤ H , W ≤ 3 × 1 0 5 1≤H,W≤3×10^5 1H,W3×105
  • 1 ≤ M ≤ m i n ( H × W , 3 × 1 0 5 ) 1≤M≤min(H×W,3×10^5) 1Mmin(H×W,3×105)
  • 1 ≤ h i ≤ H 1≤hi≤H 1hiH
  • 1 ≤ w i ≤ W 1≤w_i≤W 1wiW
  • ( h i , w i ) ≠ ( h j , w j )   ( i ≠ j ) (h_i,w_i)≠(h_j,w_j)\ (i≠j) (hi,wi)=(hj,wj) (i=j)

Input
Input is given from Standard Input in the following format:

H   W   M h 1   w 1 ⋮ h M   w M H\ W\ M\\ h_1\ w_1\\ ⋮\\ h_M\ w_M H W Mh1 w1hM wM

Output
Print the answer.

Sample Input 1 
2 3 3
2 2
1 1
1 3
Sample Output 1 
3

We can destroy all the targets by placing the bomb at ( 1 , 2 ) (1,2) (1,2).

Sample Input 2 
3 3 4
3 3
3 1
1 1
1 2
Sample Output 2 
3
Sample Input 3 
5 5 10
2 5
4 3
2 3
5 5
2 2
5 4
5 3
5 1
3 5
1 4
Sample Output 3 
6

建一棵线段树维护每一列的目标数量。枚举行,对于该行,将该行中的每一个目标在线段树维护的对应列上减一,这样线段树维护的区间中的最大值加上该行的目标数量即为选择该行时的最大值。复杂度为 O ( M log ⁡ W ) O(M\log W) O(MlogW)

#include

#define pi(a) printf("%d\n",a)
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define vi vector
#define pb push_back
using namespace std;

inline int qr() {
    int f = 0, fu = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')fu = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        f = (f << 3) + (f << 1) + c - 48;
        c = getchar();
    }
    return f * fu;
}

const int N = 3e5 + 10;

struct Seg_Tree {
    struct {
        int l, r;
        int dat;
    } t[N * 4];

    void build(int p, int l, int r) {
        t[p].l = l, t[p].r = r;
        if (l == r)return;
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
    }

    void change(int p, int x, int v) {
        if (t[p].l == t[p].r) {
            t[p].dat += v;
            return;
        }
        int mid = (t[p].l + t[p].r) >> 1;
        if (x <= mid)change(p << 1, x, v);
        else change(p << 1 | 1, x, v);
        t[p].dat = max(t[p << 1].dat, t[p << 1 | 1].dat);
    }
} tr;

vi r[N];
int n, m, k;

int main() {
    n = qr(), m = qr(), k = qr();
    tr.build(1, 1, m);
    repi(i, 1, k) {
        int x = qr(), y = qr();
        tr.change(1, y, 1), r[x].pb(y);
    }
    int ans = 0;
    repi(i, 1, n) {
        for (auto it:r[i])tr.change(1, it, -1);
        ans = max(ans, (int) r[i].size() + tr.t[1].dat);
        for (auto it:r[i])tr.change(1, it, 1);
    }
    pi(ans);
    return 0;
}

你可能感兴趣的:(线段树,ACM)