题目大意:有n个点,每次在l~r之间所有点各加上同一种地雷,或询问某一区间内地雷种数。
解题思路:首先注意是“加上”而不是“覆盖”。
然后我们用两棵线段树(树状数组),一棵维护某一区间内左端点个数,另一棵维护右端点个数。
由于每次只加上一个端点,故为单点修改。
那么如何查询呢?
如果1~r内有a个左端点,则说明最多有a种地雷,如果1~l-1内有b个右端点,则说明a种地雷中,有b种的右端点没有达到l(否则一定在l-1之后)。
那么查询出a和b,然后输出a-b即可。
很明显是区间修改。
时间复杂度$O(mlog_2 n)$。
C++ Code:
#include<cstdio> #include<cctype> #include<cstring> #define N 100005 int n,m,R,ans,d1[N<<2],d2[N<<2]; inline int readint(){ char c=getchar(); for(;!isdigit(c);c=getchar()); int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } void add1(int l,int r,int o){ ++d1[o]; if(l!=r){ int mid=l+r>>1; if(R<=mid)add1(l,mid,o<<1); if(mid<R)add1(mid+1,r,o<<1|1); } } void add2(int l,int r,int o){ ++d2[o]; if(l!=r){ int mid=l+r>>1; if(R<=mid)add2(l,mid,o<<1); if(mid<R)add2(mid+1,r,o<<1|1); } } void query1(int l,int r,int o){ if(r<=R)ans+=d1[o];else{ int mid=l+r>>1; query1(l,mid,o<<1); if(mid<R)query1(mid+1,r,o<<1|1); } } void query2(int l,int r,int o){ if(r<=R)ans+=d2[o];else{ int mid=l+r>>1; query2(l,mid,o<<1); if(mid<R)query2(mid+1,r,o<<1|1); } } int main(){ n=readint(),m=readint(); memset(d1,0,sizeof d1); memset(d2,0,sizeof d2); while(m--){ int opt=readint(),l=readint(),r=readint(); if(opt==1){ R=l; add1(1,n,1); R=r; add2(1,n,1); }else{ int Ans=0; ans=0; R=r; query1(1,n,1); Ans+=ans; ans=0; R=l-1; if(R) query2(1,n,1); Ans-=ans; printf("%d ",Ans); } } return 0; }