看到n,m<=100000可以想到这是一个考高级数据结构的题,这个区间修改区间查询让我想到了线段树和树状数组。
然而看了一遍题后眉头一皱,发现并不简单。
它要求输出区间上炸弹种类数,那么维护区间和也不对,维护区间最大值也不对,看来不能直接套模板了。
这个时候需要重新综合考虑修改和查询的内容了。经过思考可以想到离散化的方法,把区间修改改成单点修改,区间查询即为求区间∑。
那么就可以写一个树状数组了, 毕竟代码好写很多很多很多。
对于每个修改把原数组左右端点所在位置++(注意开两个数组)。
对于每次询问嘛……
我们把1-n分为三部分:tl左,tl右tr左和tr右,记为123.那么所有炸弹有左1右1,左1右2,左1右3,左2右2,左2右3,左3右3.
我们查询的答案为左1右2+左1右3+左2右2+左2右3=sum-左1右1-左3右3.这也体现了数学里的正难则反的原则。
求法上还可以进一步优化:原式=sum-askyou(l-1)-(sum-sumzuo[r])=sum-zuo[r]-you[r-1];(直接给出这个式子你们应该也能理解)
本题可A。
int i,t,tl,tr; int m,n; int zuo[1000010],you[1000010]; int lowbit(int x) { return x&(-x); } void addzuo(int p,int k) { while(p<=n) { zuo[p]+=k; p+=lowbit(p); } } void addyou(int p,int k) { while(p<=n) { you[p]+=k; p+=lowbit(p); } } int sumzuo(int x) { int ans=0; while(x) { ans+=zuo[x]; x-=lowbit(x); } return ans; } int sumyou(int x) { int ans=0; while(x) { ans+=you[x]; x-=lowbit(x); } return ans; } int main() { cin>>n>>m; for(i=1;i<=m;i++) { cin>>t>>tl>>tr; if(t==1) { addzuo(tl,1); addyou(tr,1); } else cout<<sumzuo(tr)-sumyou(tl-1)<<endl; } }
还好没有卡tl=1或等0的数据,不然就死循环…………