Mayor‘s posters(离散化+线段树)

题目传送门

Mayor’s posters

题目大意

n(n<=10000) 个人依次贴海报,给出每张海报所贴的范围 l i , r i ( 1 < = l i < = r i < = 10000000 ) l_i,r_i(1<=l_i<=r_i<=10000000) liri1<=li<=ri<=10000000) 。求出最后还能看见多少张海报。(海报只露出部分也算)

思路

首先注意到数据范围 l i , r i ( 1 < = l i < = r i < = 10000000 ) l_i,r_i(1<=l_i<=r_i<=10000000) liri1<=li<=ri<=10000000),显然直接开数组存会TLE或者MLE
所以需要离散化处理一下数据,处理的时候记得非相邻区间查一个值进去
离散化之后就是线段树处理了,每次更新数据时(即为贴上新海报的时候)值为 i i i,可以在懒惰标记下沉的时候将颜色传进去,最后查询整个线段树记录叶节点的颜色即可
具体操作可以参考大佬的解释:线段树懒惰标记操作

AC Code

#include<vector>
#include<string.h>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
const int N=2e5+9;
int flag[N];
struct node{
    int x, y;
}a[N];
struct segtree{
    int v, colour;
}tr[N<<2];
inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}
inline int lc(int p)   {return p<<1;}
inline int rc(int p)   {return p<<1|1;}
inline void build(int k, int l, int r){
    tr[k].colour=0;
    if(l==r)    return ;
    int mid=(l+r)>>1;
    build(lc(k), l, mid);
    build(rc(k), mid+1, r);
}
inline void f(int p, int k){
    tr[p].colour=k;
}
inline void push_down(int p){
    f(lc(p), tr[p].colour);
    f(rc(p), tr[p].colour);
    tr[p].colour=0;
}
// inline void push_up(int p)  {tr[p].v=max(tr[lc(p)].v, tr[rc(p)].v);}
inline void updata(int p, int l, int r, int x, int y, int k){
    if(x>r || y<l)  return ;
    if(l<=x && y<=r){
        tr[p].colour=k;
        return ;
    }  
    int mid=(x+y)>>1;
    if(tr[p].colour) push_down(p);
    updata(lc(p), l, r, x, mid, k);
    updata(rc(p), l, r, mid+1, y, k);
    // push_up(p);
}
inline void query(int p, int l, int r, int x, int y){
    if(x==y && tr[p].colour==0) return ;
    if(tr[p].colour)  {flag[tr[p].colour]=1; return ;}
    int mid=(x+y)>>1;
    // if(tr[p].tag) push_down(p);
    query(lc(p), l, r, x, mid);
    query(rc(p), l, r, mid+1, y);
}
int T, n;
vector<int>v;
int val[N]; 
int main(){
    cin>>T;
    while(T--){
        // 离散化
        memset(flag, 0, sizeof(flag));
        v.clear();
        n=read();
        for(int i=1; i<=n; i++){
            a[i].x=read(); a[i].y=read();
            v.push_back(a[i].x);
            v.push_back(a[i].y);
        }
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        val[0]=1;
        int k=1;
        for(int i=1; i<v.size(); i++){
           if(v[i]-v[i-1]==1)   k++;
           else                 k+=2;
           val[i]=k;
        }
        build(1,1,N);
        for(int i=1; i<=n; i++){
            a[i].x=val[(lower_bound(v.begin(), v.end(), a[i].x)-v.begin())];
            a[i].y=val[(lower_bound(v.begin(), v.end(), a[i].y)-v.begin())];
            updata(1,a[i].x,a[i].y,1,N,i);
        }
        query(1,1,N,1,N);
        int ans=0;
        for(int i=1; i<=n; i++) if(flag[i]) ans++;
        cout<<ans<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值