【BZOJ3821】【UOJ#46】【清华集训2014】—玄学(线段树分治)
我们发现实际上可以不用在乎给出的,可以先记录一个的系数
显然这个每次很好计算贡献
显然离线的时候我们可以用线段树分治氵过去
那在线呢?
二进制分组?
好像不太行得通,因为在一个组内可能只取一部分
继续考虑线段树分治
显然在一个操作出现之前不会被统计到
那就可以在每次加一次操作后对于已经填满的区间一下
突然发现似乎有点问题
我们没有办法每个节点维护一个序列表示被怎么修改,那样是的
但我们发现每次修改其实最多只会在原来的基础上增加个区间(考虑只有左右端点会切割出多的区间,其他的都是整体增加)
考虑对每个节点维护一个记录一下有哪些区间
合并信息的时候可以维护双指针
每次询问的时候按照线段树分治的老套路
对于一个整区间二分找到询问点的信息返回
更具体的可以参考代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=100005;
int type,n,q,tot,mod,pre,a[N];
inline void calc(int &a,int &b,int x,int y){
a=1ll*a*x%mod,b=(1ll*b*x+y)%mod;
}
struct node{
int l,r,a,b;
node(int _l,int _r,int _a,int _b):l(_l),r(_r),a(_a),b(_b){}
friend inline node operator +(node a,const node &b){
calc(a.a,a.b,b.a,b.b);return a;
}
};
vector<node>tr[N<<2];
#define pb push_back
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
void build(int u,int l,int r){
tr[u].pb(node(1,n,1,0));
if(l==r)return;
build(lc,l,mid),build(rc,mid+1,r);
}
inline void pushup(int u){
tr[u].clear();
for(int i=0,j=0,l=0;i<tr[lc].size()&&j<tr[rc].size();){
int a=tr[lc][i].a,b=tr[lc][i].b;
calc(a,b,tr[rc][j].a,tr[rc][j].b);
if(tr[lc][i].r<=tr[rc][j].r){
tr[u].pb(node(l+1,tr[lc][i].r,a,b));
l=tr[lc][i].r;
if(tr[lc][i].r==tr[rc][j].r)i++,j++;
else i++;
}
else {
tr[u].pb(node(l+1,tr[rc][j].r,a,b));
l=tr[rc][j].r,j++;
}
}
}
bool update(int u,int l,int r,int p,node k){
if(l==r){
if(k.l!=1)tr[u].pb(node(1,k.l-1,1,0));
tr[u].pb(k);
if(k.r!=n)tr[u].pb(node(k.r+1,n,1,0));
return true;
}
if(p<=mid){update(lc,l,mid,p,k);return false;}
else{
bool flag=update(rc,mid+1,r,p,k);
if(flag)pushup(u);
return true;
}
}
node query(int u,int l,int r,int st,int des,int k){
if(st==l&&r==des){
int L=0,R=tr[u].size();
while(L<=R){
int mi=(L+R)>>1;
if(tr[u][mi].l<=k&&k<=tr[u][mi].r)return tr[u][mi];
if(tr[u][mi].r<k)L=mi+1;
else R=mi-1;
}
}
if(des<=mid)return query(lc,l,mid,st,des,k);
if(mid<st)return query(rc,mid+1,r,st,des,k);
return query(lc,l,mid,st,mid,k)+query(rc,mid+1,r,mid+1,des,k);
}
int main(){
type=read()&1;
n=read(),mod=read();
for(int i=1;i<=n;i++)a[i]=read();
q=read();
while(q--){
int op=read(),l=read(),r=read();
if(type)l^=pre,r^=pre;
switch(op){
case 1:{
int a=read(),b=read();
tot++,update(1,1,N-5,tot,node(l,r,a,b));
break;
}
case 2:{
int p=read();if(type)p^=pre;
node now=query(1,1,N-5,l,r,p);
cout<<(pre=((1ll*now.a*a[p]+now.b)%mod))<<'\n';
break;
}
}
}
}