P2184 贪婪大陆

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\n",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\n",ans);
50         }
51     }
52     return 0;
53 }

 



posted @ 2020-05-11 17:38  L·S·D  阅读(185)  评论(0编辑  收藏  举报