题目传送门
分析:
对于\(T_i=1\)的情况,对于\(S_{p+i} \not= T_i\),我们发现
\(S_{p+i}\in[0,c)\)
\(S_p\in[0-ai,c-ai)\)
对于\(T_i=0\)的情况,区间取个反就可以了
于是我们知道了对于每一个\(T_i\),能做出贡献的区间,做区间加
这个区间是取模意义下的,所以可能会是两个
动态开点线段树维护\(O(mlogn)\)(其实也可以离线\(O(mlogm)\),但是好麻烦就没有写了2333)
询问时的值直接单点求和就好了
当\(T_i\)取反时,把对应区间取反就好了
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
#include<algorithm>
#define maxn 100005
#define INF 0x3f3f3f3f
using namespace std;
inline int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,m,a,b,c;
int Rt,lc[maxn<<6],rc[maxn<<6],sum[maxn<<6],tot;
int T[maxn];
int L[maxn],R[maxn];
inline void update(int &now,int l,int r,int ql,int qr,int num)
{
if(qr<l||r<ql)return;
if(!now)now=++tot;
if(ql<=l&&r<=qr){sum[now]+=num;return;}
int mid=(l+r)>>1;
update(lc[now],l,mid,ql,qr,num),update(rc[now],mid+1,r,ql,qr,num);
}
inline int query(int now,int l,int r,int p)
{
if(!now)return 0;
if(l==r)return sum[now];
int mid=(l+r)>>1;
if(p<=mid)return sum[now]+query(lc[now],l,mid,p);
else return sum[now]+query(rc[now],mid+1,r,p);
}
inline void solve(int i,int num)
{
if(T[i])
{
if(L[i]<R[i])update(Rt,0,n-1,L[i],R[i]-1,num);
else update(Rt,0,n-1,L[i],n-1,num),update(Rt,0,n-1,0,R[i]-1,num);
}
else
{
if(L[i]<R[i])update(Rt,0,n-1,0,L[i]-1,num),update(Rt,0,n-1,R[i],n-1,num);
else update(Rt,0,n-1,R[i],L[i]-1,num);
}
}
int main()
{
n=getint(),a=getint(),b=getint(),c=getint(),m=getint();
for(int i=0;i<m;i++)T[i]=(getchar()-48);
L[0]=0,R[0]=c,solve(0,1);
for(int i=1;i<m;i++)L[i]=(L[i-1]-a+n)%n,R[i]=(R[i-1]-a+n)%n,solve(i,1);
int q=getint();
while(q--)
{
int op=getint(),p=getint();
if(op&1)
{
p=(1ll*a*p+b)%n;
printf("%d\n",query(Rt,0,n-1,p));
}
else solve(p,-1),T[p]^=1,solve(p,1);
}
}