P2184 贪婪大陆
传送门:https://www.luogu.com.cn/problem/P2184
题目背景
面对蚂蚁们的疯狂进攻,小FF的Tower defence宣告失败……人类被蚂蚁们逼到了Greed Island上的一个海湾。现在,小FF的后方是一望无际的大海, 前方是变异了的超级蚂蚁。 小FF还有大好前程,他可不想命丧于此, 于是他派遣手下最后一批改造SCV布置地雷以阻挡蚂蚁们的进攻。
题目描述
小FF最后一道防线是一条长度为N的战壕, 小FF拥有无数多种地雷,而SCV每次可以在[ L , R ]区间埋放同一种不同于之前已经埋放的地雷。 由于情况已经十万火急,小FF在某些时候可能会询问你在[ L' , R'] 区间内有多少种不同的地雷, 他希望你能尽快的给予答复。
对于30%的数据: 0<=n, m<=1000;
对于100%的数据: 0<=n, m<=10^5.
输入格式
第一行为两个整数n和m; n表示防线长度, m表示SCV布雷次数及小FF询问的次数总和。
接下来有m行, 每行三个整数Q,L , R; 若Q=1 则表示SCV在[ L , R ]这段区间布上一种地雷, 若Q=2则表示小FF询问当前[ L , R ]区间总共有多少种地雷。
输出格式
对于小FF的每次询问,输出一个答案(单独一行),表示当前区间地雷总数。
输入输出样例
输入 #1
5 4 1 1 3 2 2 5 1 2 4 2 3 5
输出 #1
1 2
简而言之就是,q==1时,给l到r染上一种颜色,q==2时,询问l到r内一共有多少种颜色呐,在线区间修改,我们想到了线段树,线段树这个题是绝对可以做的,那线段树用来维护什么呢
因为要统计的是一段区间内有多少段曾经出现过的区间,我暂时的想法是在树上分别维护左端点出现的次数,右端点出现但的次数,还得知道左端点就能找到右端点的这么一组关系
然后查询的时候查区间内左端点和右端点的和-左右端点都在这个区间的数量(对于每一个左端点查询右端点是否在区间内)
不过为什么是暂时的呢,讲真,这太麻烦了,都给我想睡着了所以咱们换一种方法
只要一个区间的开头在一个节点i的左边,那么这个区间包含在区间1~i中
只要一个区间的尾部在一个节点j的左边,那么这个区间肯定不属于j之后的所有区间
所以我们只需要维护区间的开头和结尾的位置,查询时查找r之前有多少个开头-l之前有多少个结尾,就可以了
因为线段树还是有一些繁琐(码量多)
这个问题用树状数组就可以做辣
sum1 开头位置
sum2 结尾位置
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define lowbit(a) ((a)&-(a)) 5 #define clean(a,b) memset(a,b,sizeof(a)) 6 const int mod = 1e9 + 7; 7 const int inf=0x3f3f3f3f; 8 const int maxn = 2e5+9; 9 10 inline int read(){char c=getchar();int tot=1;while ((c<'0'|| c>'9')&&c!='-') c=getchar();if (c=='-'){tot=-1;c=getchar();} 11 int sum=0;while (c>='0'&&c<='9'){sum=sum*10+c-'0';c=getchar();}return sum*tot;} 12 13 int _; 14 ////////////////////////////////////////////////////////////////////////// 15 ll sum1[maxn],sum2[maxn]; 16 void update(int x,ll y,int n,ll *c)///One point update 17 { 18 for(int i=x; i<=n; i+=lowbit(i)) 19 c[i] += y; 20 } 21 ll get_sum(int x,ll *c)///Interval query 22 { 23 ll ans = 0; 24 for(int i=x; i; i-=lowbit(i)) 25 ans += c[i]; 26 return ans; 27 } 28 ////////////////////////////////////////////////////////////////////////// 29 int main() 30 { 31 int n=read(); 32 int m=read(); 33 for(int i=1;i<=m;i++) 34 { 35 int q=read(); 36 if(q==1) 37 { 38 int l=read(); 39 int r=read(); 40 update(l,1,n,sum1); 41 update(r,1,n,sum2); 42 } 43 else 44 { 45 // for(int i=1;i<=10;i++) printf("%lld %lld ",sum1[i],sum2[i]); 46 int l=read(); 47 int r=read(); 48 ll ans=get_sum(r,sum1)-get_sum(l-1,sum2); 49 printf("%lld ",ans); 50 } 51 } 52 return 0; 53 }