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;
}