题目描述
校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的…… 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: K=1,读入l,r表示在l~r之间种上的一种树 K=2,读入l,r表示询问l~r之间能见到多少种树(l,r> 0)
输入
第一行n,m表示道路总长为n,共有m个操作接下来m行为m个操作
输出
对于每个k=2输出一个答案
样例输入
54
1 1 3
2 2 5
1 2 4
2 3 5
样例输出
1
2
解题思路:
这道题用树状数组极其简单,在此不解释。
用线段树来做,要复杂一些。要建立sl,sr来记录和,实际上与树状数组中的a[2][50005]没有太大的区别。
代码:(请不要直接拷贝哦)
//树状数组 #include <cstdio> int n,m,x,y,z,a[2][50005]; using namespace std; inline int read() { int f=1,x=0; char ch=getchar(); if (ch=='-') { f=-1; ch=getchar(); } while ((ch<'0')||(ch>'9')) ch=getchar(); while ((ch>='0')&&(ch<='9')) { x=x*10+ch-48; ch=getchar(); } return f*x; } inline void change(int x,int y) { int i=x; while (i<=n) a[y][i]++,i+=i&(-i); } inline int sum(int x,int y) { int i=x,s=0; while (i>0) s+=a[y][i],i-=i&(-i); return s; } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) { z=read(),x=read(),y=read(); if(z==1) change(x,0),change(y,1); else printf("%d\n",sum(y,0)-sum(x-1,1)); } return 0; }
//线段树 #include <cstdio> int n,m,x,y,z; using namespace std; struct TREE{ int l,r; int sl,sr; }tree[200005]; inline int read() { int f=1,x=0; char ch=getchar(); if (ch=='-') { f=-1; ch=getchar(); } while ((ch<'0')||(ch>'9')) ch=getchar(); while ((ch>='0')&&(ch<='9')) { x=x*10+ch-48; ch=getchar(); } return f*x; } inline void build(int root,int l,int r) { tree[root].l=l; tree[root].r=r; if (l==r) return; int mid=(l+r)/2; build(root*2,l,mid); build(root*2+1,mid+1,r); } inline void change_left(int root,int x) { int l=tree[root].l,r=tree[root].r; if ((l==x)&&(r==x)) { tree[root].sl++; return; } int mid=(l+r)/2; if (x<=mid) change_left(root*2,x); if (x>mid) change_left(root*2+1,x); tree[root].sl=tree[root*2].sl+tree[root*2+1].sl; } inline void change_right(int root,int x) { int l=tree[root].l,r=tree[root].r; if ((l==x)&&(r==x)) { tree[root].sr++; return; } int mid=(l+r)/2; if (x<=mid) change_right(root*2,x); if (x>mid) change_right(root*2+1,x); tree[root].sr=tree[root*2].sr+tree[root*2+1].sr; } inline int find_left(int root,int l,int r) { int nl=tree[root].l,nr=tree[root].r; int mid=(nl+nr)/2; if ((l<=nl)&&(nr<=r)) return tree[root].sl; if (l>mid) return find_left(root*2+1,l,r); else if (r<=mid) return find_left(root*2,l,r); else return find_left(root*2,l,r)+find_left(root*2+1,l,r); } inline int find_right(int root,int l,int r) { int nl=tree[root].l,nr=tree[root].r; int mid=(nl+nr)/2; if ((l<=nl)&&(nr<=r)) return tree[root].sr; if (l>mid) return find_right(root*2+1,l,r); else if (r<=mid) return find_right(root*2,l,r); else return find_right(root*2,l,r)+find_right(root*2+1,l,r); } int main() { n=read(),m=read(); build(1,1,n); for (int i=1;i<=m;i++) { z=read(),x=read(),y=read(); if (z==1) { change_left(1,x); change_right(1,y); } else { int ans=find_left(1,1,y); if (x>1) ans-=find_right(1,1,x-1); printf("%d\n",ans); } } return 0; }