Mayor's posters
题目
有一面墙,现在有M张海报要贴,海报的高度和墙的高度一样,每张海报会给出区间范围[l,r],问最终墙上可见的海报有多少张?
墙的宽度:
分析
首先这题的墙的范围很大,所以必须离散化,然后在离散化之后的数据上建立线段树。
要点
这题对于染色后连续的区间[l,r]有可能离散化会在建立线段树的时候分开,所以最好在区间[l,r]中间加一个点[l,mid,r],这样如果染色[l,r],就会pushdown到[l,mid],[mid+1,r]。 但是数据比较谁水,不加也能过
AC代码(无插点)插点也很简单
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll maxn = 1e5+10;
ll T,M;
set<int> st;
struct node{
ll l,r,tag;//tag: 海报标记
}tr[4*maxn];
int arr[1000010],tail;//用于离散化
int op[1000010][2];
void pushup(ll u){
node &fa = tr[u],&L = tr[u*2],&R = tr[u*2+1];
if(L.tag == R.tag){//海报往上传递
fa.tag = L.tag;
}else{
fa.tag = 0;
}
}
void pushdown(ll u){
node &fa = tr[u],&L = tr[u*2],&R = tr[u*2+1];
if(fa.tag){ //海报往下覆盖
L.tag = fa.tag;
R.tag = fa.tag;
}
}
void build(ll u,ll l,ll r){
if(l == r){
tr[u] = {l,r,1};
}else{
tr[u] = {l,r};
ll mid = (l+r)>>1;
build(u*2,l,mid);
build(u*2+1,mid+1,r);
pushup(u);
}
}
void modify(ll u,ll l,ll r,ll tag){
if(tr[u].l>=l && tr[u].r<=r){
tr[u].tag = tag;
}else{
pushdown(u);
ll mid = tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u*2,l,r,tag);
if(r>mid) modify(u*2+1,l,r,tag);
pushup(u);
}
}
void query(ll u,ll l,ll r){
if(tr[u].tag){
st.insert(tr[u].tag);
}else{
query(u*2,l,r);
query(u*2+1,l,r);
}
}
int ind(int x){
return lower_bound(arr,arr+tail,x)-arr + 1;//因为线段树管理的下标我是1开始的,所以+1
}
int main(){
cin>>T;
while(T--){
st.clear();
tail = 0;
scanf("%lld",&M);
for(int i = 0;i<M;i++){
scanf("%d%d",&op[i][0],&op[i][1]);
arr[tail++] = op[i][0];
arr[tail++] = op[i][1];
}
sort(arr,arr+tail);
tail = unique(arr,arr+tail)-arr;
build(1,1,tail);
int tag = 1;
for(int i = 0;i<M;i++){
modify(1,ind(op[i][0]),ind(op[i][1]),tag);
tag++;
}
query(1,1,tail);
cout<<st.size()<<endl;
}
return 0;
} 
京公网安备 11010502036488号