//有一些题给出的区间很大, 但区间数量不多, 这个时候数组肯定是开不了这么大的, 所以需要进行离散化.
板子题
//模板
const int maxn=2e5+5;
int n,m;
int a[maxn], vis[maxn];
vector<int>ve;
struct node {
int tl, tr; ll val, lazy;
void fun(ll tmp){
lazy = tmp;
val = tmp;
}
}tre[maxn<<2];
struct edge {
int l,r;
}q[maxn];
void build(int id, int l, int r) {
tre[id].tl = l; tre[id].tr = r;
tre[id].val = tre[id].lazy = 0;
if(l+1 == r) return ;
int mid = (l+r) >> 1;
build(id<<1, l, mid);
build(id<<1|1, mid, r);
}
void pushdown(int id) {
if(tre[id].lazy) {
tre[id<<1].fun(tre[id].lazy);
tre[id<<1|1].fun(tre[id].lazy);
tre[id].lazy = 0;
}
}
void update(int id,int ul,int ur,int val) {
int l = tre[id].tl, r = tre[id].tr;
if(ul <= l && r <= ur) {
tre[id].lazy = val;
tre[id].val = val;
return ;
}
pushdown(id);
int mid = (l+r) >> 1;
if(ul < mid ) update(id<<1, ul, ur, val); // 因为是区间,不能再去等于了.
if(ur > mid ) update(id<<1|1, ul, ur, val);
}
int query(int id,int ql,int qr) {
int l = tre[id].tl,r = tre[id].tr;
if(l + 1 == r){
if(!vis[tre[id].val]){
vis[tre[id].val] = 1;
return 1;
}
return 0;
}
pushdown(id);
int mid = (l+r) >> 1;
if(qr < mid) return query(id<<1, ql, qr);
else if(ql > mid) return query(id<<1|1, ql, qr);
else return query(id<<1, ql, qr) + query(id<<1|1, ql, qr);
}
int getid(int x) {
return lower_bound(ve.begin(),ve.end(),x)-ve.begin()+1;
}
void solve() {
scanf("%d%d",&n, &m); ve.clear();
for(int i = 1 ; i <= n ; i ++) {
scanf("%d%d",&q[i].l, &q[i].r);
ve.push_back(q[i].l);
ve.push_back(q[i].r);
}
sort(ve.begin(), ve.end());
ve.erase(unique(ve.begin(), ve.end()), ve.end());
build(1, 1, ve.size());
for(int i = 1 ;i <= n ; i ++) {
int l = getid(q[i].l);
int r = getid(q[i].r);
update(1, l, r, i);
}
Fill(vis,0); vis[0] = 1;
printf("%d\n",query(1, 1, ve.size()));
}
//解释版
const int maxn=2e5+5;
int n,m;
int a[maxn], vis[maxn];
vector<int>ve;
struct node {
int tl, tr; ll val, lazy;
void fun(ll tmp){
lazy = tmp;
val = tmp;
}
}tre[maxn<<2];
struct edge {
int l,r;
}q[maxn];
void build(int id, int l, int r) {
tre[id].tl = l; tre[id].tr = r;
tre[id].val = tre[id].lazy = 0;
if(l+1 == r) return ;
//最后全部构造成一段一段. 而普通的线段树最后构造的一个一个的点.
int mid = (l+r) >> 1;
build(id<<1, l, mid);
build(id<<1|1, mid, r);
//这里注意下,既然是建造一段一段的,所以右区间不再是中间加1,而直接取mid.
}
void pushdown(int id) {
if(tre[id].lazy) {
tre[id<<1].fun(tre[id].lazy);
tre[id<<1|1].fun(tre[id].lazy);
tre[id].lazy = 0;
}
}
void update(int id,int ul,int ur,int val) {
int l = tre[id].tl, r = tre[id].tr;
if(ul <= l && r <= ur) {
tre[id].lazy = val;
tre[id].val = val;
return ;
}
pushdown(id);
int mid = (l+r) >> 1;
if(ul < mid ) update(id<<1, ul, ur, val); // 因为是区间,不能再去等于了.
if(ur > mid ) update(id<<1|1, ul, ur, val);
}
int query(int id,int ql,int qr) {
int l = tre[id].tl,r = tre[id].tr;
if(l + 1 == r){
// 表示当前这一段所被贴的海报编号,起来防止0的影响,故事先把0先处理一下.
if(!vis[tre[id].val]){
vis[tre[id].val] = 1; //算了当前海报后,需要标记一下.
return 1;
}
return 0;
}
pushdown(id);
int mid = (l+r) >> 1;
if(qr < mid) return query(id<<1, ql, qr); //同理.
else if(ql > mid) return query(id<<1|1, ql, qr);
else return query(id<<1, ql, qr) + query(id<<1|1, ql, qr);
}
int getid(int x) {
return lower_bound(ve.begin(),ve.end(),x)-ve.begin()+1;
}
void solve() {
scanf("%d%d",&n, &m); ve.clear();
for(int i = 1 ; i <= n ; i ++) {
scanf("%d%d",&q[i].l, &q[i].r);
ve.push_back(q[i].l);
ve.push_back(q[i].r);
}
sort(ve.begin() ,ve.end()); //离散化去重
ve.erase(unique(ve.begin(), ve.end()), ve.end());
build(1, 1, v.size());
//建造一颗离散化后这么长的线段树.
for(int i=1;i<=n;i++){
int l = getid(q[i].l);
int r = getid(q[i].r);
update(1, l, r, i); //更新这个区间贴的海报!如果后面这个区间被覆盖了
//那么区间的val值就会被覆盖,所以我们最后统计出现了val种类就是答案
}
Fill(vis,0); vis[0] = 1; //方便判断
printf("%d\n",query(1, 1, ve.size())); //后面访问到的都是一条一条的线段.
}