P3740 [HAOI2014]贴海报 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
![](https://img-blog.csdnimg.cn/img_convert/26ae2b0363184122a35f05e765573458.png)
线段树
#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;
}