贪婪大陆——(树状数组)

面对蚂蚁们的疯狂进攻,小 FF 的 Tower defence 宣告失败……人类被蚂蚁们逼到了Greed Island 上的一个海湾。现在,小 FF 的后方是一望无际的大海, 前方是变异了的超级蚂蚁。 小 FF 还有大好前程,他可不想命丧于此, 于是他派遣手下最后一批改造 SCV布置地雷以阻挡蚂蚁们的进攻。
小 FF 最后一道防线是一条长度为 N 的战壕, 小 FF 拥有无数多种地雷,而 SCV 每次可以在[ L , R ]区间埋放同一种不同于之前已经埋放的地雷。 由于情况已经十万火急,小FF 在某些时候可能会询问你在[ L’ , R’] 区间内有多少种不同的地雷, 他希望你能尽快的给予答复。
输入
第一行为两个整数 n 和 m; n 表示防线长度, m 表示 SCV 布雷次数及小 FF 询问 的次数总和。
接下来有 m 行, 每行三个整数 Q,L , R;
若 Q=1 则表示 SCV 在[ L , R ]这段区间 布上一种地雷,
若 Q=2 则表示小 FF 询问当前[ L , R ]区间总共有多少种地雷。
输出
对于小 FF 的每次询问,输出一个答案(单独一行),表示当前区间地雷总数
样例输入
5 4
1 1 3
2 2 5
1 2 4
2 3 5
样例输出
1
2
提示
【数据范围】
对于 30%的数据: 0<=n, m<=1000;
对于 100%的数据: 0<=n, m<=10^5.

本来以为是维护区间加1区间最值查询,但果然错了

要维护的是区间种类查询

可以这样做

把左区间和右区间分别当作左括号和右括号,那么每一个左括号就是一个区间的开始,每一个右括号就是一个区间的结束

那么对于每一个查询的区间 [ l , r ] [l,r] ,那么区间中地雷的个数就是1—r中左括号的个数(也就是前面埋了有多少种地雷)减去1–(l-1)中右括号的个数(也就是前面埋完了多少种地雷)

那我们只需要两个树状数组来分别维护左括号和右括号就是了

代码

#include<bits/stdc++.h>
using namespace std;
inline int read(){
 char ch=getchar();
 int res=0;
 while(!isdigit(ch)) ch=getchar();
 while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
 return res;
}
int t1[100005],t2[100005],n,m;
inline int lowbit(int k)
{
 return k&(-k);
}
inline int add(int l,int r)
{
 while(l<=n)
 {
  t1[l]++;
  l+=lowbit(l);
 }
 while(r<=n)
 {
  t2[r]++;
  r+=lowbit(r);
 }
}
inline int query(int l,int r)
{
 l--;
 int ans1=0,ans2=0;
 while(r>0)
 {
  ans1+=t1[r];
  r-=lowbit(r);
 }
 while(l>0)
 {
  ans2+=t2[l];
  l-=lowbit(l);
 } 
 return ans1-ans2;
}
int main(){
 n=read(),m=read();
 int q,l,r;
 for(int i=1;i<=m;i++)
 {
  q=read(),l=read(),r=read();
  if(q==1) add(l,r);
  else cout<<query(l,r)<<'\n';
 }
 return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42555009/article/details/82860231