一、解题思路:
通过题目中要求维护的
移除 中的树(区间修改)
询问 中树的棵数(区间查询)
两个操作,不难看出是一道使用线段树维护的数据结构题。
二、优化:
由于数据范围达到 ,所以显然直接以线段树 的效率是无法通过的。 怎么办呢?
我们发现,在这里我们每个叶子节点的权值只有 和 ,并且没有区间加操作,这说明当一个区间被修改过后,它的总权值以及内部的任何区间权值均为 ,更形象地说,它 “失去利用价值”,不需要在任何操作和询问中再被修改和查询到了。
于是,我们果断放弃懒标记,而以该区间是否 总权为零作为是否有“利用价值”(势能)的判断方式。此时,无论它被修改区间或是查询区间覆盖多少,它都不会对线段树或是查询结果产生影响。因此,我们成功地通过一个小优化通过了此题。
最后的最后,代码:
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e6+10;
int n,m,tree[N<<2];
void pushup(int p){
tree[p]=tree[p<<1]+tree[p<<1|1];
return;
}
void build(int p,int l,int r){
if(l==r){
tree[p]=1;
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
return;
}
void modify(int p,int l,int r,int x,int y){
if(y<l||r<x) return;
if(tree[p]==0) return;
if(x<=l&&r<=y){
tree[p]=0;
return;
}
int mid=(l+r)>>1;
modify(p<<1,l,mid,x,y);
modify(p<<1|1,mid+1,r,x,y);
pushup(p);
return;
}
int query(int p,int l,int r,int x,int y){
if(y<l||r<x) return 0;
if(tree[p]==0) return 0;
if(x<=l&&r<=y) return tree[p];
int mid=(l+r)>>1,ans=0;
ans+=query(p<<1,l,mid,x,y);
ans+=query(p<<1|1,mid+1,r,x,y);
return ans;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
build(1,1,n);
while(m--){
int op,x,y;
cin>>op>>x>>y;
if(op==1) modify(1,1,n,x,y);
else cout<<query(1,1,n,x,y)<<'\n';
}
return 0;
}