[HAOI2014]贴海报(线段树/浮水法)

P3740 [HAOI2014]贴海报 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

线段树
#include <bits/stdc++.h>
#include <iostream>
#include<unordered_map>
#define x first
#define y second
#define  ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);

using namespace std;

typedef  long  long LL ;
typedef  unsigned long  long ULL ;
typedef pair<int,int> PII ;
typedef pair<LL,int> PLI ;
const int N = 1e7 + 10 ,M=1000 + 10;
const LL INF2 = 1e17;


int n,v,ans,m,cur,A[M ],B[M ];
bool flag,col[N << 2 ];

void pushup(int u)// 当前这个区间 海报 是否 都已经出现了
{
    col[u] = col[u << 1 ] & col[u << 1|1];
}

void modify(int u,int l,int r,int L,int R)
{
    if(col[u]) return; // 当前一小段 海报 都已经能出现了
    if(L <= l && r <= R ) // [L,R]完全包含[l,r] ,旧出现的广告 完全包含 新出现的广告, 旧的海报可以出现
    {
        flag= 1;col[u] = 1;
        return;
    }

    int mid = l + r >> 1; // 对 后出现的 海报 分半
    if(L <= mid ) modify(u<<1,l,mid,L,R);
    if(R >mid ) modify(u<<1|1,mid +1,r,L,R);


    pushup(u);// 看一下 这段区间的 海报是不是 都已经出现了
}


inline void solve()
{
    cin >> n >> m;
    for(int i=1;i<= m ;i ++ )
    cin >> A[i] >> B[i] ;

    for(int i=m ;i ;i -- )
    {
        flag =0;
        modify(1,1,n,A[i],B[i]);
        if(flag ) ans ++;

    }

    cout  << ans << endl ;



}
signed main()
{
    ios
    int T=1;
//    cin>>T;
    while(T -- )
    {
        solve();

    }


    return 0;
}

浮水法
浮水法,没有悬念。
不过这里比较简单,只需要记录某一个线段是不是(或者是有一部分)浮到了最上面。
上浮思想:设竖直平面中存在有一些高度不同的线段,当一个线段上方没有被其他线段挡着时,这个线段就可以上浮,如果一个线段(或是它的一部分)可以上浮到无限高,那么显然,这个线段(或这一部分)所在的高度是他所覆盖的这一个数轴范围内(将平面的无限低的地方看做有一个数轴)最高的。
浮水法其实是一个递归的过程,首先,当一条线段满足上浮的条件时,让他上浮(用 while 循环控制),但是当他不满足上浮的条件时,将他被挡住的那一段切掉,然后接着递归的让他剩下的那部分上浮。
一开始要用排序进行预处理。
因为有高度为零的情况,所以可以一开始先在最底部画一条线段,使这一条线段的初始高度为零,这样应该为零的地方是上浮不起来的。

#include <bits/stdc++.h>
#include <iostream>
#include<unordered_map>
#define x first
#define y second
#define  ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);

using namespace std;

typedef  long  long LL ;
typedef  unsigned long  long ULL ;
typedef pair<int,int> PII ;
typedef pair<LL,int> PLI ;
const int N = 1e7 + 10 ,M=1000 + 10;
const LL INF2 = 1e17;


int n,v,ans,m,cur,A[M ],B[M ];
bool flag,col[N << 2 ];

void pushup(int u)// 当前海报 
{
    col[u] = col[u << 1 ] & col[u << 1|1];
}

void modify(int u,int l,int r,int L,int R)
{
    if(col[u]) return; // 当前海报已经能出现了
    if(L <= l && r <= R ) // [L,R]完全包含[l,r] ,旧出现的广告 完全包含 新出现的广告, 旧的海报可以出现
    {
        flag= 1;col[u] = 1;
        return;
    }

    int mid = l + r >> 1; // 对 后出现的 海报 分半
    if(L <= mid ) modify(u<<1,l,mid,L,R);
    if(R >mid ) modify(u<<1|1,mid +1,r,L,R);


    pushup(u);
}


inline void solve()
{
    cin >> n >> m;
    for(int i=1;i<= m ;i ++ )
    cin >> A[i] >> B[i] ;

    for(int i=m ;i ;i -- )
    {
        flag =0;
        modify(1,1,n,A[i],B[i]);
        if(flag ) ans ++;

    }

    cout  << ans << endl ;



}
signed main()
{
    ios
    int T=1;
//    cin>>T;
    while(T -- )
    {
        solve();

    }


    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值