这题其实只需要暴力求解即可,也只要O(nm)。但是用一下线段树,大力出奇迹不好吗,也可以随便练练线段树。
线段树值得注意的是——空间要开4倍大,虽然实际空间只有2倍,但是它并不是一棵完全二叉树。
还有一点就是坐标轴是从0开始的,而我从1开始,导致我调试了好久才发现。
#include#include #include #include using namespace std; const int maxn=10010; int n,m; int getin(){ int num=0,t=1; char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(c<='9'&&c>='0'){num=num*10+c-'0';c=getchar();} return num*t; } struct Yzyet{int mark,num;}tree[4*maxn];//线段树一般开4倍的空间 //mark即懒标记,num保存当前树的个数 void build(int root,int l,int r){//建树 tree[root].mark=0; if(l==r){tree[root].num=1;return;} int mid=(l+r)/2; build(root*2,l,mid); build(root*2+1,mid+1,r); tree[root].num=tree[root*2].num+tree[root*2+1].num; } void pushdown(int root,int l,int r){//向下传递mark int mid=(l+r)/2; int &ma=tree[root].mark; if(ma!=0&&l!=r){ tree[root*2].mark=tree[root*2+1].mark=ma; tree[root*2].num=tree[root*2+1].num=0;//该区间内已无树 ma=0; } } int ask(int root,int l,int r,int x,int y){//询问答案,其实不需要这个 直接输出tree[1]即可 if(x>r||y return 0; if(x<=l&&r<=y) return tree[root].num; pushdown(root,l,r); int mid=(l+r)/2; return (ask(root,l,mid,x,y)+ask(root,mid+1,r,x,y)); } void change(int root,int l,int r,int x,int y,int add){//进行修改 if(x>r||y return; if(x<=l&&r<=y){ tree[root].mark+=add; tree[root].num=0;//该区间内已无树 return; } pushdown(root,l,r); int mid=(l+r)/2; change(root*2,l,mid,x,y,add); change(root*2+1,mid+1,r,x,y,add); tree[root].num=tree[root*2].num+tree[root*2+1].num; } int main() { n=getin()+1;m=getin(); //因为坐标轴是从0开始的,所以n+=1 build(1,1,n); for(int i=1;i<=m;i++){ int x,y; x=getin()+1;y=getin()+1; //同理x、y也要加1 change(1,1,n,x,y,1); } printf("%d\n",ask(1,1,n,1,n));//没有必要,直接输出tree[1]即可 return 0; }
本文由Yzyet编写,网址为www.cnblogs.com/Yzyet。非Yzyet同意,禁止转载,侵权者必究。