校门外的树
校门外有很多树,学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两种操作:
- K=1,读入 l,r 表示在 l 到 r 之间种上一种树,每次操作种的树的种类都不同;
- K=2,读入 l,r 表示询问 l 到 r 之间有多少种树。
注意:每个位置都可以重复种树。
输入格式
第一行 n,m 表示道路总长为 n,共有 m 个操作;
接下来 m 行为 m 个操作。
输出格式
对于每个 k=2 输出一个答案。
样例
样例输入
5 4
1 1 3
2 2 5
1 2 4
2 3 5
样例输出
1
2
数据范围与提示
对于 20\%20% 的数据,1≤n,m≤100;
对于 60% 的数据,1≤n≤10^3,1≤m≤5×10^4;
对于 100% 的数据,1≤n,m≤5×10^4,保证l,r>0。
________________________________________________________________________________________________________
题目的实际意思就是,求当前线段与前面多少条线段有交叉。
利用括号序列,(:表示一条线段的开始,):表示一条线段的结束。
那么有多少线段与当前线段(l,r)交叉,就是r前面开始的线段树减去l前面结束的线段数。即r前的( 数减去l前的 ) 数,用两个树状数组维护 ( 和 ) 的数量就可以了
________________________________________________________________________________________________________
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=5e4+10; 4 int a[maxn],b[maxn]; 5 int n,m; 6 inline int lowbit(int x) 7 { 8 return x&-x; 9 } 10 void update(int *p,int x) 11 { 12 for(int i=x;i<=n;i+=lowbit(i))++p[i]; 13 } 14 int get(int *p,int x) 15 { 16 int ans=0; 17 for(int i=x;i;i-=lowbit(i))ans+=p[i]; 18 return ans; 19 } 20 int main() 21 { 22 scanf("%d%d",&n,&m); 23 for(int op,x,y,i=0;i<m;++i) 24 { 25 scanf("%d%d%d",&op,&x,&y); 26 if(op==1) 27 { 28 update(a,x); //( 29 update(b,y); //) 30 } 31 else 32 { 33 printf("%d\n",get(a,y)-get(b,x-1)); 34 } 35 } 36 return 0; 37 }