POJ 2528 Mayor’s posters(离散化+成段更新)

本文介绍了一种使用离散化和线段树的数据结构方法来解决大规模海报覆盖问题的技术方案。通过离散化处理坐标并利用线段树进行区间更新和查询,有效地解决了海报相互覆盖后的可见数量计算难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报

思路:这题数据范围很大,直接搞超时+超内存,需要离散化+线段树

此题re了N次,MAX越开越大,开始以为后台数据比实际范围大,其实是离散化+去重+加点后,MAX最多能到达3*MAX,然后建线段树最好要4*3*MAX大小。


#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <climits>//形如INT_MAX一类的
#define MAX 11111
#define INF 0x7FFFFFFF
#define REP(i,s,t) for(int i=(s);i<=(t);++i)
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define L(x) x<<1
#define R(x) x<<1|1
# define eps 1e-5
//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂
using namespace std;

struct node {
    int l,r,mid,cover;
} tree[MAX*12];
int n;
int l[MAX],r[MAX],x[4*MAX],xx[4*MAX],vis[MAX];

int search(int v,int n) {
    int ll = 1,rr = n,mid;
    while(ll <= rr) {
        mid = (ll + rr) >> 1;
        if(v > xx[mid]) ll = mid + 1;
        if(v == xx[mid]) return mid;
        if(v < xx[mid]) rr = mid - 1;
    }
}

void down(int x) {
    if(tree[x].cover != -1) {//此条件很重要,否则就sb了
        tree[L(x)].cover = tree[R(x)].cover = tree[x].cover;
        tree[x].cover = -1;
    }
}
void build(int l,int r,int num) {
    tree[num].l = l;
    tree[num].r = r;
    tree[num].mid = (l+r) >> 1;
    tree[num].cover = -1;
    if(l == r)
        return ;
    build(l,tree[num].mid,L(num));
    build(tree[num].mid + 1,r,R(num));
}

void update(int l,int r,int num,int color) {
    if(l <= tree[num].l && r >= tree[num].r) {
        tree[num].cover = color;
        return ;
    }
    down(num);
    if(r <= tree[num].mid) {
        update(l,r,L(num),color);
    } else if( l > tree[num].mid) {
        update(l,r,R(num),color);
    } else {
        update(l,tree[num].mid,L(num),color);
        update(tree[num].mid+1,r,R(num),color);
    }

}

int query(int l,int r,int num) {
    if(tree[num].cover != -1) {
        if(vis[tree[num].cover] == 0) {
            vis[tree[num].cover] = 1;
            return 1;
        }
        return 0;
    }
    if(r <= tree[num].mid) {
        return query(l,r,L(num));
    } else if(l > tree[num].mid) {
        return query(l,r,R(num));
    } else {
        return query(l,tree[num].mid,L(num)) + query(tree[num].mid+1,r,R(num));
    }
}

void test(int n) {
    for(int i=1; i<=3*n; i++) {
        printf("l:%d r:%d cover:%d\n",tree[i].l,tree[i].r,tree[i].cover);
    }
}

int main() {

    int tt,i;
    cin >> tt;
    while(tt --) {
        scanf("%d",&n);
        int cnt = 0;
        for(i=0; i<n; i++) {
            scanf("%d%d",&l[i],&r[i]);
            x[cnt++] = l[i];
            x[cnt++] = r[i];
        }
        sort(x,x+cnt);
        int m = 1;
        for (i=1; i<cnt; i++) { //离散化去重
            if (x[i] != x[i-1]) x[m ++] = x[i];
        }
        for (i=m-1; i>0; i --) { //加点解决边缘冲突
            if (x[i] != x[i-1] + 1) x[m ++] = x[i-1] + 1;
        }
        sort(x,x+m);
        int t = 0;
        for(i=0; i<m; i++) {
            xx[++t] = x[i];
        }
        build(1,t,1);
        for(i=0; i<n; i++) {
            update(search(l[i],t),search(r[i],t),1,i);
        }
        memset(vis,0,sizeof(vis));
        cout << query(1,t,1) << endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值