题意分析
题意很简单
一开始想用一个bitset维护,明显这个是超内存的。但是我为什么还要写
然后想了一下,能不能维护每次种树的左右区间来写,然而发现并不行。
接着想,维护种类和维护区间没办法了,能不能在种树的次数上下功夫呢?
我想维护一个种了树和没种树的线段树,询问就是查询区间内中了树的最大值和没种树的最小值,最后做一个差,这样的话样例是过的。写完交上去WA了,自己想了一个样例吧自己叉掉了。为什么我不提前想一下呢?
然后就想,肯定是维护种植的次数的关系。苦苦思考无果。看了看大佬的题解,思路泉涌思路如下:
还是思考种了树和没种树的关系,其实他们互为补集,这是非常明显的。
每次种树,所种树的种类也是不同的,这也是显而易见的,也就是如果当前种了n次树,那么现在街道上一定有n种树对吧?
好了,所以对于每一次查询,我们只需要知道,对于这段区间,有多少种树是重复的,然后做差就可以得到结果了。
所以问题就转换为,如何维护所种树是重复的。由于每次种树,不种树的区间被种树的区间分为了两段,所以这样维护左右两半部分比较方便,况且对于下面求解问题也是较为简便的。所以这里要分左右两部分计算。
下面举例说明算法的思想。
1. 街道长为[1,100],首先在[30,60]种树,那么左边没有种树的区间L[1,29],右边R[61,100],我们将这个区间分别加一(分别的意思是左右要用不同的线段树维护)。
2. 假如我们要查询[20,40]种树的信息。由于现在种树中了1次,所有tot=1。关键来了,想办法去重,重复的如何计算呢?在没有种树的左区间中查询右端点,在没有种树的右区间中查询左端点,也就是在L[1,29]中查询60,在R[61,100]中查询30,显然,均为0 ,所以结果就是tot-0-0 = 1
3. 大家可以举例子自己尝试,关键就是【在没有种树的左区间中查询右端点,在没有种树的右区间中查询左端点】,然后用种树的从次数减去即可
代码总览
#include<bits/stdc++.h>
using namespace std;
const int nmax = 60001;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef struct{
int l,r,ll,rr;
int mid() { return ((l+r) >>1 );}
}Tree;
Tree tree[nmax<<2];
int hashback[nmax];
int n,m;
inline void pushdown(int rt){
if(tree[rt].ll){
tree[rt<<1].ll += tree[rt].ll;
tree[rt<<1|1].ll += tree[rt].ll;
tree[rt].ll = 0;
}
if(tree[rt].rr){
tree[rt<<1].rr += tree[rt].rr;
tree[rt<<1|1].rr += tree[rt].rr;
tree[rt].rr = 0;
}
}
void build(int l, int r, int rt){
tree[rt].l = l , tree[rt].r = r;
tree[rt].ll = tree[rt].rr = 0;
if(tree[rt].l == tree[rt].r){hashback[tree[rt].l] = rt; return;}
build(l,tree[rt].mid(),rt<<1);
build(tree[rt].mid() + 1 ,r, rt<<1|1);
}
void lupdate(int l, int r, int rt){
// if(tree[rt].l >r || tree[rt].r < l) return;
if(tree[rt].l >= l && tree[rt].r <= r){
tree[rt].ll ++;
return;
}
// if(tree[rt].l == tree[rt].r) return;
if(tree[rt].l != tree[rt].r) pushdown(rt);
if(l<=tree[rt].mid()) lupdate(l,r,rt<<1);
if(r>tree[rt].mid()) lupdate(l,r,rt<<1|1);
// lupdate(l,r,rt<<1);
// lupdate(l,r,rt<<1|1);
}
void rupdate(int l, int r, int rt){
// if(tree[rt].l >r || tree[rt].r < l) return;
if(tree[rt].l >= l && tree[rt].r <= r){
tree[rt].rr ++;
return;
}
// if(tree[rt].l == tree[rt].r) return;
if(tree[rt].l != tree[rt].r) pushdown(rt);
if(l<=tree[rt].mid()) rupdate(l,r,rt<<1);
if(r>tree[rt].mid()) rupdate(l,r,rt<<1|1);
// rupdate(l,r,rt<<1);
// rupdate(l,r,rt<<1|1);
}
int lQuery(int pos, int rt){
if(tree[rt].l == pos && tree[rt].r == pos) return tree[rt].ll;
if(tree[rt].l != tree[rt].r) pushdown(rt);
if(pos<= tree[rt].mid()) return lQuery(pos,rt<<1);
if(pos > tree[rt].mid()) return lQuery(pos,rt<<1|1);
}
int rQuery(int pos , int rt){
if(tree[rt].l == pos && tree[rt].r == pos) return tree[rt].rr;
if(tree[rt].l != tree[rt].r) pushdown(rt);
if(pos<= tree[rt].mid()) return rQuery(pos,rt<<1);
if(pos > tree[rt].mid()) return rQuery(pos,rt<<1|1);
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d %d",&n,&m);
build(0,n,1);
int k,a,b;
int tot = 0;
for(int i = 0;i<m;++i){
scanf("%d %d %d",&k,&a,&b);
if(k == 1){
tot ++;
lupdate(0,a-1,1);
rupdate(b+1,n,1);
}else{
int tt = lQuery(b,1);
int ttt = rQuery(a,1);
printf("%d\n",tot - tt - ttt);
}
}
return 0;
}