题面:
给一个n长的数列,m次询问; 单点更改 或 询问区间中 某数出现次数;
此题涉及区间维护,显然数据结构。线段树或树状数组;由于满足区间加减,直接上树状数组;
问题在如何维护某数出现次数。。。
根据数据范围,数值的范围在 maxlongint 中 ,如果使用常规的方法:每一个数维护一个树状数组,显然爆炸。
所以不难想到,
无法直接在线回答;思路转为离线;
首先我们要压缩空间: 我们思考询问的性质;对于 种类k ,我们只需要知道数列中有哪些是k;每一个数是k或不是两种情况。
显然,每一个种类的数是互不相干扰的;把对于同种类的数的操作按照时间序一起处理,然后清空树状数组即可;
离线排序降维压缩时间;
(注意此处清空可用memset 也可以对点删除)
#include<bits/stdc++.h>
using namespace std;
#define in rd()
#define int long long
#define gc getchar()
inline int rd(){
char c=gc;int num=0,f=1;
for(;!isdigit(c);c=gc)if(c=='-')f=-1;
for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
return f*num;
}
const int maxn=4e5+10;
int c[maxn];
int n,m;
inline int lowbit(int k){return k&(-k);}
inline void _add(int k,int v){for(;k<=n;k+=lowbit(k))c[k]+=v;}
inline int query(int k){int ans=0;for(;k>0;k-=lowbit(k))ans+=c[k];return ans;}
struct task{
int t,f,k,l,r;
}t[maxn];
int a[maxn],top=0;
struct rep{
int t,s;
bool operator <(const rep &a) const{
return t<a.t;
}
}r[maxn];
int up=0;
bool cmp(task a,task b){
if(a.k==b.k)return a.t<b.t;
return a.k<b.k;
}
signed main(){
n=in,m=in;
for(int i=1;i<=n;i++){
int x=in;
t[++top]=(task){0,0,x,i,0};
a[i]=x;
}
for(int i=1;i<=m;i++){
char c;cin>>c;
if(c=='C'){
int loc=in,b=in;
t[++top]=(task){i,1,a[loc],loc,0};
t[++top]=(task){i,0,b,loc,0};
a[loc]=b;//×¢òa£?μ±?°μü′úDèòa′?′¢×?D??é??
}
else{
int l=in,r=in,k=in;
t[++top]=(task){i,2,k,l,r};
}
}
for(int i=1;i<=n;i++){
t[++top]=(task){m+1,1,a[i],i,0};
}
sort(t+1,t+top+1,cmp);
for(int i=1;i<=top;i++){
if(t[i].f==0){
_add(t[i].l,1);
// cerr<<t[i].l<<query(t[i].l)<<endl;
}
else{
if(t[i].f==1){
_add(t[i].l,-1);
}
else{
r[++up].s=query(t[i].r)-query(t[i].l-1);
// cerr<<r[up].s<<endl;
r[up].t=t[i].t;
}
}
}
sort(r+1,r+up+1);
for(int i=1;i<=up;i++)printf("%lld\n",r[i].s);
return 0;
}