BSOJ3214 UOJ46【清华集训2014】玄学
题目
给出很多个形如:\((l,r,a,b)\) 的操作,表示让区间 \([l,r]\) 当中的数变成 \(x\to (ax+b)\mod p\)
(其中 \(p\) 是初始给定的。)
然后多次询问 \((l,r,pos)\) 表示询问:如果执行区间 \([l,r]\) 当中的操作,那么第 \(pos\) 个数的值是多少。
分析
先考虑没有第二个区间限制(就是查询当前的 \(a[pos]\) 的值),有一个很奇怪的做法:
对于每一个操作,分成三个这样的部分:\((1,0,l-1),(a,b,r),(1,0,n)\) ,每一个操作\((a,b,pos)\)的意思是:对于 \([laspos+1,pos]\) 的所有数都有变化:\(x\to (ax+b)\mod p\) 。
然后我们对所有的操作二进制分组,容易发现合并(修改部分)的复杂度是 \(O(n\log n)\) 的,因为就算把所有操作合并起来,也就只会把原序列分成 \(O(n)\) 级别段。(就类似是差分,合并就是差分标记的合并,具体可以见代码)
接下来考虑查询。
发现其实就是从当前的二进制分组的vector(里面保存的是操作合并后)里从左往右进行查询,也就是在每一个里面二分 \(pos\) 的位置,找到当前这个vector当中第一个位置大于等于 \(pos\) 的,然后对 \(ans=a[pos]\) 进行这个节点对应的 \((a,b)\) 的操作。
这样做是 \(O(m\log^2 n)\) 的。
然后考虑有区间限制的做法。
考虑线段树维护二进制分组的过程,于是查询就变成了线段树上递归下去的 \(\log\) 个区间,修改就是正常的二进制分组,只不过用了线段树维护。
然后就结束了,时间复杂度 \(O(n\log n+m\log^2 n)\) 。
代码
#include<bits/stdc++.h>
using namespace std;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
template <typename T>
inline void read(T &x){
x=0;char ch=gc();bool f=false;
while(!isdigit(ch)){if(ch=='-'){f=true;}ch=gc();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
#define int long long
const int N=1e6+5;
int n,m,a[N],typ,MOD,tot,Ans;
inline int mul(const int &a,const int &b){return 1ll*a*b%MOD;}
inline int add(const int &a,const int &b){return a+b>=MOD?a+b-MOD:a+b;}
struct node{
int a,b,r;
node(int x=0,int y=0,int z=0){a=x,b=y,r=z;}
friend inline node operator + (const node &a,const node &b){return node(mul(a.a,b.a),add(mul(a.b,b.a),b.b),min(a.r,b.r));}
friend inline bool operator < (const node &a,const node &b){
if(a.r^b.r) return a.r<b.r;
if(a.a^b.a) return a.a<b.a;
return a.b<b.b;
}
};
vector<node>t[N<<2];
inline void Merge(vector<node>&Now,vector<node>L,vector<node>R){//合并两个操作序列
unsigned int l=0,r=0;
while(l<L.size()&&r<R.size()){
Now.push_back(L[l]+R[r]);
if(L[l].r==R[r].r) l++,r++;
else if(R[r].r<L[l].r) r++;
else l++;
}
return ;
}
void Modify(int p,int l,int r,const int &x,const int &y,const int &a,const int &b){
if(l==r){
t[p].push_back(node(1,0,x-1));
t[p].push_back(node(a,b,y));
if(y^n) t[p].push_back(node(1,0,n));
return;
}
int mid=(l+r)>>1;
if(tot<=mid) Modify(p<<1,l,mid,x,y,a,b);
else Modify(p<<1|1,mid+1,r,x,y,a,b);
if(tot==r) Merge(t[p],t[p<<1],t[p<<1|1]);
return ;
}
void Query(int p,int l,int r,int ql,int qr,int pos){
if(ql<=l&&qr>=r){
int x=lower_bound(t[p].begin(),t[p].end(),node(0,0,pos))-t[p].begin();
Ans=add(mul(Ans,t[p][x].a),t[p][x].b);return;
}
int mid=(l+r)>>1;
if(ql<=mid) Query(p<<1,l,mid,ql,qr,pos);
if(qr>mid) Query(p<<1|1,mid+1,r,ql,qr,pos);
return ;
}
signed main(){
read(typ),typ=typ&1,read(n),read(MOD);
for(int i=1;i<=n;i++) read(a[i]);read(m);
for(int i=1;i<=m;i++){
int op,l,r,b,c;
read(op),read(l),read(r);
if(typ) l^=Ans,r^=Ans;
if(op==1){
read(b),read(c);
b%=MOD,c%=MOD;++tot;
Modify(1,1,m,l,r,b,c);
}
else{
int pos;read(pos);
if(typ) pos^=Ans;Ans=a[pos];
Query(1,1,m,l,r,pos);
write(Ans),putchar('\n');
}
}
return 0;
}

浙公网安备 33010602011771号