[Codeforces 220B]Little Elephant and Array(扫描线)(树状数组)
首先感谢光哥的样例,这是光哥的博客
这里是原题链接
原题题意:
给出一个长度为n的序列,进行m次询问。
每次询问区间[l,r]内,有多少个数字x刚好出现了x次(出现次数和他数值本身相等)。
题目思路:
有的是,直接上莫队,优化询问.本博客用莫队的思想(排序查询)+扫描线的思想+树状数组去实现的
枚举右端点r,维护左端点l,设法将sum(l,r)表示为区间内的合法数字个数
以区间[2,2,2,2]为例,下标从1开始:
1.r=1时,向右滚动左端点,其sum(l,r)分别为:[0,‘还没到这里’,‘还没到这里’,‘还没到这里’];
'0’出现的原因是:sum(1,1)不合法,所以贡献为0.
2.r=2时,向右滚动左端点,其sum(l,r)分别为:[1,0,还没到这里,还没到这里];
"1"出现的原因是:区间[1,2]内都为2,个数刚好为2个,满足要求,所以此处的sum(1,2)为1.
3.r=3时,向右滚动左端点,其sum(l,r)分别为:[−1,1,0,还没到这里];
我们从右向左解释,r=3,此时最右侧的sum(3,3)为0没问题,sum(2,3)=1,出现的理由同上, 区间[1,3]内有3个数字2,不满足条件,所以sum(1,3)必须为0,所以我们构造时令下标为1处为"-1",这样求和时sum(1,3)就为0了.
4.r=4时,向右滚动左端点,其sum(l,r)分别为:[0,−1,1,0];
此时的查询结果:
sum(4,4)=0,sum(3,4)=1,sum(2.4)=0,sum(1,4)=0.
合理合法.怎么查询都对.
所以可以看出规律,只需要维护上述规律即可将贡献维护。
查询时树状数组就可以完成任务
还没看懂的话,一定要看代码旁的注释:
multiset:点击了解
树状数组:点击了解
扫描线:点击了解
AC代码:
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b)<