# 【SDOI2008】 郁闷的小J woj1717

题面:
给一个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;
	
	
	
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值