JZOJ5943. 【NOIP2018模拟11.01】树

在这里插入图片描述

Data Constraint

对于前 30% 的数据, n, q ≤ 100;
对于另 20% 的数据, 没有操作 1;
对于另 20% 的数据, 没有操作 3;
对于 100% 的数据, n, q ≤ 10^5, ai ≤ 10^9, k ≤ 2^30, 1 ≤ l ≤ r ≤ n.

题解

题目的意思就是要维护一个序列,而且还有修改操作。
最简单的是第二个操作,直接就线段树解决,
接下来在考虑一下第三个操作,
显然它就是求区间里面任意两个数的和的平方的和。
可以通过维护一次方和与二次方和然后将他们组合一下就可以得到答案。
现在关键问题就是解决掉第一个操作,
它是一个and操作,也就是说在二进制状态下,值有可能是1->0或者0->0。
再认真思考一下,其实最多1的个数只有31n个,
这样算下来,对于操作1就直接暴力处理就可以了。

code

#include<cstdio>
#include<algorithm>
#define ll long long
#define ls (x<<1)
#define rs (x<<1|1)
#define M ((l+r)>>1)
using namespace std;
const int N=100003,mo=998244353;
int n,m,k,cz,opl,opr,a[N],si[N*4],id,z[33],anss;
ll ans,ans1,ans2,s[N*4],s1[N*4],s2[N*4];
bool bz[33][N*4];
char ch;
void read(int& n)
{
	for(ch=getchar();ch<'0' || ch>'9';ch=getchar());
	for(n=0;'0'<=ch && ch<='9';ch=getchar())n=(n<<1)+(n<<3)+ch-48;
}
void updata(int x)
{
	s1[x]=s1[ls]+s1[rs];
	s2[x]=(s2[ls]+s2[rs])%mo;
	s[x]=(s[ls]+s[rs]+s2[ls]*si[rs]%mo+s2[rs]*si[ls]%mo+(s1[ls]%mo)*(s1[rs]%mo)*2%mo)%mo;
}
void build(int x,int l,int r)
{
	if(l==r)
	{
		s1[x]=a[l];
		s2[x]=(ll)a[l]*a[l]%mo;
		s[x]=0;
		si[x]=1;
		return;
	}
	int m=M;
	build(ls,l,m);
	build(rs,m+1,r);
	si[x]=si[ls]+si[rs];
	updata(x);
}
void work(int x,int l,int r)
{
	bz[id][x]=1;
	if(l==r)
	{
		a[l]=a[l]&k;
		s1[x]=a[l];
		s2[x]=(ll)a[l]*a[l]%mo;
		s[x]=0;
		return;
	}
	int m=M;
	work(ls,l,m);
	work(rs,m+1,r);
	updata(x);
}
void change(int x,int l,int r)
{
	if(bz[id][x])return;
	if(opl<=l && r<=opr)
	{
		work(x,l,r);
		return;
	}
	int m=M;
	if(opl<=m)change(ls,l,m);
	if(m<opr)change(rs,m+1,r);
	updata(x);
}
void find(int x,int l,int r)
{
	if(opl<=l && r<=opr)
	{
		ans=(ans+s[x]+s2[x]*anss%mo+ans2*si[x]%mo+(ans1%mo)*(s1[x]%mo)*2%mo)%mo;
		ans1=ans1+s1[x];
		ans2=(ans2+s2[x])%mo;
		anss=anss+si[x];
		return;
	}
	int m=M;
	if(opl<=m)find(ls,l,m);
	if(m<opr)find(rs,m+1,r);
}
int main()
{
	//freopen("ex_seg2.in","r",stdin);
	freopen("seg.in","r",stdin);
	freopen("seg.out","w",stdout);
	z[0]=1;for(int i=1;i<31;i++)z[i]=z[i-1]<<1;
	read(n);
	for(int i=1;i<=n;i++)read(a[i]);
	build(1,1,n);
	for(read(m);m;m--)
	{
		read(cz);read(opl);read(opr);
		if(cz==1)
		{
			read(k);
			for(id=0;id<31;id++)
				if((k&z[id])==0)change(1,1,n);
		}
		else
		if(cz==2)
		{
			ans=ans1=ans2=anss=0;
			find(1,1,n);
			printf("%lld\n",ans1);
		}
		else
		{
			ans=ans1=ans2=anss=0;
			find(1,1,n);
			ans=(ans*2+ans2*4)%mo;
			printf("%lld\n",ans);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/83656533
今日推荐