ODT

1.将序列中连续的相同的元素整合,用一个三元组(L,R,val)来表示
2.用set维护

struct node {
	int l,r;//左右端点 
	mutable LL v;//这个区间内的值是多少 
	node(int L,int R=-1,LL V=0):l(L),r(R),v(V){}
	bool operator<(const node& o)const{
		return l<o.l;
	} 
};

set<node> s; 

int qmi(int a,int k,int p){int res=1;while(k){if(k&1) res=res*a%p;a=a*a%p;k>>=1;}return res;}

set<node>::iterator split(int pos){//找到一段区间,然后插入[l,pos-1],[pos,r],并返回pos 
	auto it=s.lower_bound(node(pos));//找到第一个大于等于l的点
	if(it!=s.end()&&it->l==pos) return it; 
	--it;
	if(pos>it->r) return s.end();
	int L=it->l,R=it->r;
	LL V=it->v;
	s.erase(it);
	s.insert(node(L,pos-1,V));
	return s.insert(node(pos,R,V)).first;//返回一个迭代器 
	//pair<iterator,bool> insert(const value_type& val),insert函数的类型 
}

//区间和操作 
void add(int l,int r,LL val=1){
	split(l);
	auto itr=split(r+1),itl=split(l);
	for(;itl!=itr;++itl) itl->v+=val;
} 

//区间赋值操作 
void assign(int l,int r,LL val=0){
	split(l);
	auto itr=split(r+1),itl=split(l);
	s.erase(itl,itr);
	//iterator erase(const_iterator first,const_iterator last);
	s.insert(node(l,r,val));
}

//求区间第k小的数,如果reversed=1,那么就是求区间第k大
LL rank(int l,int r,int k,bool reversed=0){
	if(reversed) k=r-l+2-k;
	split(l);
	auto itr=split(r+1),itl=split(l);
	vector<PII> vp;
	for(;itl!=itr;++itl) vp.push_back({itl->v,itl->r-itl->l+1});
	sort(vp.begin(),vp.end());
	for(auto i:vp){
		k-=i.second;
		if(k<=0) return i.first;
	}
	return -1; 
}
//求幂次和 
LL sum(int l,int r,int ex,int mod){ 
	split(l);
	auto itr=split(r+1),itl=split(l);
	LL res=0;
	for(;itl!=itr;++itl) res=(res+(LL)(itl->r-itl->l+1)*qmi(itl->v,ex,mod))%mod;
	return res;
}
posted @ 2024-07-09 10:43  MENDAXZ  阅读(23)  评论(0编辑  收藏  举报