Jzoj P1495 宝石___线段树+扫描线+离散化

题目大意:

在一个 MM M ∗ M 的正方形平面中,给出 N N 个宝石的坐标 (xi,yi) ( x i , y i ) ,每个宝石的价值为 Ai A i ,有一块 KK K ∗ K 的布,问能覆盖的宝石的最大价值和是多少,宝石在布的边缘也算。

1m50000,1n50000,1k10000 1 ≤ m ≤ 50000 , 1 ≤ n ≤ 50000 , 1 ≤ k ≤ 10000

分析:

https://blog.csdn.net/gx_man_vip/article/details/80833641
跟这题比较类似,不过注意一下,边缘能够覆盖,所以右边缘不需要 1 − 1
然后每个矩形的上面的扫描线的纵坐标 y2 y 2 ,要变成 y2+1 y 2 + 1 ,因为边缘需要,所以在 y2+1 y 2 + 1 维护而不能在 y2 y 2 时维护

代码:

#include  
#include
#include
#include
#include
#define N 500005   

using namespace std;  

struct Node {  
    int l, r, h, add;    
}c[N];  
struct Note {  
    int Lzy, Max;  
    int l, r;
}a[5 * N];
int x[N];

bool cmp(Node aa, Node bb) {  
    if (aa.h != bb.h) return aa.h < bb.h;
    return aa.add < bb.add;
}  

void Build_tree(int G, int l, int r) {  
    a[G].l = l, a[G].r = r;  
    a[G].Max = a[G].Lzy = 0;  
    if (l == r)  return;  
    int mid = (l + r) >> 1;  
    Build_tree(G * 2, l, mid);  
    Build_tree(G * 2 + 1, mid + 1, r);  
}  

int Get_id(int num, int l, int r) {  
    while (l <= r) {  
        int mid = (l + r) >> 1;
        if (x[mid] == num) return mid;    
        if (x[mid] < num) l = mid + 1;  
                     else r = mid - 1;  
    }  
    return l;
}  

double Get_max(int G) {   
    return max(a[G * 2].Max, a[G * 2 + 1].Max);    
}  

void Insert_tree(int G, int x1, int x2, int add) {  
    if (a[G].l == x1 && a[G].r == x2) {  
        a[G].Lzy += add;  
        a[G].Max += add;
        return;  
    } 
    a[G * 2].Lzy += a[G].Lzy, a[G * 2].Max += a[G].Lzy;
    a[G * 2 + 1].Lzy += a[G].Lzy, a[G * 2 + 1].Max += a[G].Lzy;
    a[G].Lzy = 0;
    int mid = (a[G].l + a[G].r) >> 1;  
    if (x2 <= mid) Insert_tree(G * 2, x1, x2, add);  
              else if (x1 > mid) Insert_tree(G * 2 + 1, x1, x2, add);  
                            else {  
                                 Insert_tree(G * 2, x1, mid, add);  
                                 Insert_tree(G * 2 + 1, mid + 1, x2, add);  
                            }  
    a[G].Max = Get_max(G); 
}  
int main() { 
    int x1, y1, z1, ans;
    int tot = 0, m, n, k;
    scanf("%d %d %d", &m, &n, &k);  
    for (int i = 1; i <= n; i++) {  
         scanf("%d %d %d", &x1, &y1, &z1);  
         x[++tot] = x1, 
         c[tot].l = x1, c[tot].r = min(x1 + k, m), 
         c[tot].h = y1, c[tot].add = z1;
         x[++tot] = min(x1 + k, m), 
         c[tot].l = x1, c[tot].r = min(x1 + k, m), 
         c[tot].h = min(y1 + k + 1, m + 1), c[tot].add = -z1;
    }  
    sort(c + 1, c + tot + 1, cmp);  
    sort(x + 1, x + tot + 1); 
    int cnt = 1;  
    for (int i = 2; i <= tot; i++)   
         if (x[i] != x[i - 1]) x[++cnt] = x[i];   
    ans = 0;  
    Build_tree(1, 1, cnt);  
    for (int i = 1; i <= tot; i++) {
         int x1 = Get_id(c[i].l, 1, cnt);  
         int x2 = Get_id(c[i].r, 1, cnt);  
         if (x1 <= x2) Insert_tree(1, x1, x2, c[i].add);  
         ans = max(ans, a[1].Max);
    }          
    printf("%d\n", ans);  
    return 0;  
}  

你可能感兴趣的:(C++,线段树,离散,扫描线)