很明显的一道线段树的“区间修改+区间查询”
区间修改:在第i次区间修改,将【l,r】内数字改为i,如果区间内是同一张海报,用lazy——tag标记。
区间查询:统计区间内有多少种lazy,用vis数组辅助标记。
很明显,题目中给出的【l,r】范围过大,容易爆内存,而n很小,从而考虑离散化数据。
离散化的过程中要注意的是,题目中将墙分为多个小格,如果两个数据之间相差为一就是普通赋值即可,但是如果出现1,500,7000,10000(【1,10000】【1,500】【7000,10000】)这类情况时,若离散化为1,2,3,4就会得到错误答案,因为500与7000并不相邻。于是对于这种数据我们就要在之间插入一个数,使得离散化时他们不相邻;
离散化主打的就是一个sort+unique+二分(
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <math.h>
#include <cstdio>
#define ll long long
#define pii pair<int,int>
#define lowbit(x) (x&(-x))
#define endl "\n"
using namespace std;
//众所周知,poj不能用万能头
const int N = 1e5+10;//开太小会爆re或wa
struct node{
int l,r;
int lazy;
}t[N<<2];
int num[N<<1],vis[N<<1],ans;
void build(int i,int l,int r){
t[i].l=l;
t[i].r=r;
t[i].lazy=0;
if(l==r){
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
}
void push_down(int i){
if(t[i].lazy==0)
return;
t[i<<1].lazy=t[i<<1|1].lazy=t[i].lazy;
t[i].lazy=0;
}
void update(int i,int l,int r,int v){
if(t[i].l>=l&&t[i].r<=r){
t[i].lazy=v;
return;
}
push_down(i);
int mid=(t[i].l+t[i].r)>>1;
if(l<=mid)update(i<<1,l,r,v);
if(r>mid)update(i<<1|1,l,r,v);
}
void query(int i,int l,int r)
{
if(t[i].lazy&&!vis[t[i].lazy]){
ans++;
vis[t[i].lazy]=1;
return;
}
if(t[i].l==t[i].r)return;
push_down(i);
int mid=(t[i].l+t[i].r)>>1;
query(i<<1,l,r);
query(i<<1|1,l,r);
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int c;
cin>>c;
while(c--){
int n;
cin>>n;
ans=0;
memset(vis,0,sizeof vis);
int k=1;
vector<pii>a;
for(int i=1;i<=n;i++){
int l,r;
cin>>l>>r;
a.push_back({l,r});
num[k++]=l;
num[k++]=r;
}
sort(num+1,num+k);
int m=unique(num+1,num+k)-(num+1);
int kk=m;
for(int i=2;i<=m;i++){//特殊处理
if(num[i]-num[i-1]>1){
num[++kk]=num[i-1]+1;
}
}
sort(num+1,num+kk+1);
build(1,1,kk);
for(int i=0;i<n;i++){
int p=lower_bound(num+1,num+kk+1,a[i].first)-num;
int q=lower_bound(num+1,num+kk+1,a[i].second)-num;
update(1,p,q,i+1);
}
query(1,1,kk);
cout<<ans<<endl;
}
return 0;
}