CF896C 一种vector写法
这里介绍一种 vector 写法(来自某位 dalao)
首先,用
struct Seg{int l,r; ll v;};
vector<Seg> vec;
那么当要涉及的区间跨越了这结构上的区间时候,就要进行区间分裂了。
-
假设要分裂开的区间是
[u,v] ,如果存在l,r (在一个Seg内) 使得l<u\leq r ,此时就可以将[l,r] 分裂为[l,u-1],[u,r] 两个区间。(对于v 的处理之后再做)。 -
若
\exists [l,r]|(l\leq v<r) ,则[l,r]\to[l,v],[v+1,r] 。这样保证了区间的完整性。 -
如果 对于操作1 不存在这样的
[l,r] ,则一定存在l=u 或者l 超过了左右边界;如果 对于操作2 不存在这样的[l,r] ,则一定存在r=v 或者r 超过了左右边界。事实上,由于取模的原因,l,r 不可能越界。故此时无需分裂区间,直接加入即可。
对于步骤1,在此位置的
这里要注意了,在
示例代码:
void split(int l,int r){
for(auto it=vec.begin();it!=vec.end();++it){
auto[u,v,w]=*it; if(u<l&&l<=v){
it->l=l,vec.insert(it,{u,l-1,w}); break; }
//由于没有引用,所以可以直接这么写
}
for(auto it=vec.begin();it!=vec.end();++it){
auto[u,v,w]=*it; if(u<=r&&r<v){
it->l=r+1,vec.insert(it,{u,r,w}); break; }
}
}
对于操作1,先 split 开
split(l,r);
for(auto&[u,v,w]:vec)
if(l<=u&&v<=r) w+=x;
对于操作2,先 split 开
split(l,r);
for(wz1=0;l>vec[wz1].l;) ++wz1;
for(wz2=wz1;wz2<vec.size()&&vec[wz2].r<=r;) ++wz2;
vec.erase(vec.begin()+wz1,vec.begin()+wz2); //[l,r)
vec.insert(vec.begin()+wz1,{l,r,x});
对于操作3,找区间第
vector<pair<ll,int>> px;
for(auto[u,v,w]:vec)
if(u<=r&&l<=v) px.push_back({w,min(v,r)-max(u,l)+1});
sort(px.begin(),px.end());
for(auto[p,q]:px)
if((x-=q)<=0){cout<<p<<'\n'; break;}
操作4,只要 Seg区间 与
y=rnd()%vmax+1,ans=0;
for(auto[u,v,w]:vec)
if(u<=r&&l<=v)
(ans+=1ll*(min(v,r)-max(u,l)+1)*qpow(w,x,y)%y)%=y;
cout<<ans<<'\n';
结语:这份代码其实还不够完美,可以用二分找第一个
想看代码实现细节的,戳这里 完整代码