感谢宇巨抛过来的题
题目大意:
给出一个长度为n的序列,进行m次询问。
每次询问区间 [ l , r ] [l,r] [l,r]内,有多少个数字 x x x刚好出现了 x x x次。
题目思路:
类比维护区间内出现了多少种数字
用扫描线+树状数组的去考虑
枚举右端点
r
r
r,维护左端点
l
l
l,设法将
s
u
m
(
l
,
r
)
sum(l,r)
sum(l,r)表示为区间内的合法数字
个数
所以以区间 [ 2 , 2 , 2 , 2 ] [2,2,2,2] [2,2,2,2]为例:
1.
r
=
1
r = 1
r=1,左端点的贡献分别为:
[
0
,
0
,
0
,
0
]
[0,0,0,0]
[0,0,0,0];
2.
r
=
2
r = 2
r=2,左端点的贡献分别为:
[
1
,
0
,
0
,
0
]
[1,0,0,0]
[1,0,0,0];
3.
r
=
3
r = 3
r=3,左端点的贡献分别为:
[
−
1
,
1
,
0
,
0
]
[-1,1,0,0]
[−1,1,0,0];
4.
r
=
4
r = 4
r=4,左端点的贡献分别为:
[
0
,
−
1
,
1
,
0
]
[0,-1,1,0]
[0,−1,1,0];
所以可以看出规律,只需要维护上述规律即可将贡献维护成前缀和。
Code:
/*** keep hungry and calm CoolGuang! ***/
//#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 2e5+700;
const int M = 1e6+8;
const ll mod= 1e6+7;
const double eps = 1e-9;
const double PI = acos(-1);
auto random_address = [] { char *p = new char; delete p; return uint64_t(p); };
const uint64_t SEED = chrono::steady_clock::now().time_since_epoch().count() * (random_address() | 1);
mt19937_64 rng(SEED);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
ll a[maxn],sum[maxn];
void add(int pos,int val){
while(pos<=n){
sum[pos] += val;
pos += pos&-pos;
}
}
ll query(int pos){
ll ans = 0;
while(pos){
ans += sum[pos];
pos -= pos&-pos;
}return ans;
}
vector<pair<int,int>>q[maxn];
ll res[maxn];
multiset<int>s[maxn];
int main(){
read(n);read(m);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=m;i++){
int x,y;
read(x);read(y);
if(x>y) swap(x,y);
q[y].push_back({x,i});
}
for(int i=1;i<=n;i++){
if(a[i]<=n){
s[a[i]].insert(i);
int sz = s[a[i]].size();
if(sz == a[i]+1){
int sp = *s[a[i]].begin(),tp = *next(s[a[i]].begin());
int temp = query(sp)-query(sp-1);
add(sp,-temp-1);
add(tp,1);
}else if(sz == a[i]){
int sp = *s[a[i]].begin();
add(sp,1);
}else if(sz == a[i]+2){
int sp = *s[a[i]].begin(),tp = *next(s[a[i]].begin()),tpp = *next(next(s[a[i]].begin()));
int temp = query(sp)-query(sp-1);
int tempx = query(tp)-query(tp-1);
add(sp,-temp);
add(tp,-tempx-1);
add(tpp,1);
s[a[i]].erase(sp);
}
}
for(auto x:q[i])
res[x.second] = query(i)-query(x.first-1);
}
for(int i=1;i<=m;i++){
printf("%lld\n",res[i]);
}
return 0;
}
/***