联考20200525 T2 「雅礼集训 2018 Day7」B

题目传送门

分析:
对于\(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);
	}
}

posted @ 2020-05-25 21:54  Izayoi_Doyo  阅读(226)  评论(0编辑  收藏  举报