Poj-2528 Mayor's posters (离散+线段树)

Mayor’s posters

题目链接: Mayor’s posters POJ - 2528

题意

给你n(1 < n < 10000)个海报,每个海报有l和r(1<=l<=r<=1e7),代表自己覆盖的区间,后面的会覆盖前面的,求总共会当最后一个覆盖结束后有多少海报可以看见。
补充,这里的离散化其实有点问题的,例子1-10,1-1,3-10.如果不好的离散会输出2.

经研究最好的离散是在插入l,r两个点的时,把l+1,l-1,r+1,r-1都离散化,这样一定不会出问题。


思路

本题的难点在于修改的l,r区间非常的大,如果直接开数组,暴力跑线段树那么非常容易T,我们又发现了另外一点,就是总共只有1e4个海报,就是只有2e4个有效点,另外的都无所谓,所以先把数据存起来离线即可。


代码

#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cstdio>
#include <string>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <sstream>
#include <memory>
#include <iostream>
#include <algorithm>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back

typedef double db;
typedef long long ll;
const int MAXN = (int)2e4+7;
const int INF = (int)0x3f3f3f3f;

inline int read() { int c = 0, f = 1;char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1;ch = getchar();}
    while (ch >= '0' && ch <= '9') {c = c * 10 + ch - '0';ch = getchar();}
    return c * f;
}

#define lson rt<<1
#define rson rt<<1|1

int A[MAXN],N;
int tot = 0;

struct tre{
    int sum;
    int add;
}tree[MAXN<<2];

void PushDown(int rt,int ln,int rn){
    if (tree[rt].add){
        tree[lson].sum = tree[rt].add;
        tree[rson].sum = tree[rt].add;

        tree[lson].add = tree[rt].add;
        tree[rson].add = tree[rt].add;
        tree[rt].add = 0;
    }
}

void Update(int L,int R,int C,int l,int r,int rt){
    if (L <= l && r <= R){
        tree[rt].sum = C;
        tree[rt].add = C;
        return ;
    }
    int m = (l+r)>>1;
    PushDown(rt,m+1-l,r-m);
    if (L <= m) Update(L,R,C,l,m,lson);
    if (R >  m) Update(L,R,C,m+1,r,rson);
}

void Down(int l,int r,int rt) {
    if (l == r) {
        A[l] = tree[rt].sum;
        return;
    }
    PushDown(rt,1,1);
    int m = l+r>>1;
    Down(l,m,lson);
    Down(m+1,r,rson);
}

set<int>se;

vector<int> vp;
int getID(int x) {return lower_bound(vp.begin(),vp.end(),x)-vp.begin()+1; }
struct Node {
    int l,r;
    Node(int l = 0,int r = 0):l(l),r(r){}
}qst[MAXN];

int main()
{
    int T;
    scanf("%d",&T);
    while (T --) {

        int M = read(); N = 2e4;
        tot = 0;mmm(tree,0);se.clear();vp.clear();

        rep(i,1,M) {
            int l = read(),r = read();
            qst[i] = Node(l,r);
            vp.pb(l),vp.pb(r);
        }
        sort(vp.begin(),vp.end());vp.erase(unique(vp.begin(),vp.end()),vp.end());

        rep(i,1,M) {
            int l = getID(qst[i].l);
            int r = getID(qst[i].r);
            Update(l,r,++tot,1,N,1);
        }

        Down(1,N,1);
        rep(i,1,N) {
            if (se.count(A[i]) == 0)se.insert(A[i]);
        }
        se.erase(0);
        printf("%d\n",se.size());
        mmm(tree,0);tot = 0;se.clear();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值