正题
原题是清华集训2014的玄学。
因为对于i到j操作进行询问,所以考虑对操作建一棵线段树,每一个点存有一些区间,对于每一个点,这些区间的并为,每个区间存有两个值,对于这个区间内的每一个数k,表示经过我所管理的线段树操作后,会变成。
可以把这些区间转化成多个断点,每次加入一个询问操作会多两个断点,对于线段树上的一条链贡献,所以断点个数总和不超过,但是遍历一条链,加断点的时间复杂度是不正确的,考虑一棵线段树的子树,当且仅当它满的时候,才把左右儿子进行合并,因为之前不可能访问到线段树中的这个节点。
合并两个端点可以直接过一遍,复杂度跟断点个数相关,所以插入时间复杂度还是
查询的时候,在线段树上找到对应的节点,二分找到对应的,把它们合并即可。
#include<bits/stdc++.h>
#define ls now<<1
#define rs now<<1|1
using namespace std;
const int N=100010;
int T,n,mod,m,t=0;
int A[N];
struct node{
int l,r,a,b;
node operator+(const node q)const {return (node){0,0,1ll*a*q.a%mod,(1ll*b*q.a%mod+q.b)%mod};}
}X;
vector<node> tr[N*10];
void calc(int &a,int &b,int c,int d){
a=1ll*a*c%mod,b=1ll*c*b%mod+d;
b>=mod?b-=mod:0;
}
void upload(int now){
int a,b,l=0;
for(int i=0,j=0;i<tr[ls].size() && j<tr[rs].size();){
a=tr[ls][i].a;b=tr[ls][i].b;
calc(a,b,tr[rs][j].a,tr[rs][j].b);
if(tr[ls][i].r<=tr[rs][j].r){
tr[now].push_back((node){l+1,tr[ls][i].r,a,b});
l=tr[ls][i].r;
if(tr[ls][i].r==tr[rs][j].r) i++,j++;
else i++;
}
else tr[now].push_back((node){l+1,tr[rs][j].r,a,b}),l=tr[rs][j].r,j++;
}
}
bool insert(int now,int x,int l,int r,node F){
if(l==r){
if(F.l>1) tr[now].push_back((node){1,F.l-1,1,0});
tr[now].push_back(F);
if(F.r<n) tr[now].push_back((node){F.r+1,n,1,0});
return true;
}
int mid=(l+r)/2;
if(x<=mid) {insert(ls,x,l,mid,F);return false;}
else if(insert(rs,x,mid+1,r,F)) {upload(now);return true;}
else return false;
}
node get_ans(int now,int x,int y,int k,int l,int r){
if(x==l && y==r){
int l=0,r=tr[now].size()-1;
while(l<=r){
int mid=(l+r)/2;
if(tr[now][mid].r<k) l=mid+1;
else if(tr[now][mid].l<=k && k<=tr[now][mid].r) return tr[now][mid];
else r=mid-1;
}
}
int mid=(l+r)/2;
if(y<=mid) return get_ans(ls,x,y,k,l,mid);
else if(mid<x) return get_ans(rs,x,y,k,mid+1,r);
else return get_ans(ls,x,mid,k,l,mid)+get_ans(rs,mid+1,y,k,mid+1,r);
}
int main(){
scanf("%d %d %d",&T,&n,&mod);T=T&1;
for(int i=1;i<=n;i++) scanf("%d",&A[i]);
scanf("%d",&m);
int tot=m;
int type,x,y,a,b;
long long last=0;
while(m--){
scanf("%d %d %d %d",&type,&x,&y,&a);
if(T) x^=last,y^=last;
if(!type){
scanf("%d",&b);
t++;insert(1,t,1,tot,(node){x,y,a,b});
}
else{
if(T) a^=last;
X=get_ans(1,x,y,a,1,tot);
printf("%lld\n",last=(1ll*A[a]*X.a%mod+X.b)%mod);
}
}
}