Description
Input
第一行一个整数 n 表示序列长度, 接下来一行 n 个整数描述这个序列.
第三行一个整数 q 表示操作次数, 接下来 q 行每行一次操作, 格式同题目描述.
Output
输出等同于操作 2, 3 次数之和的行数, 每行一个非负整数表示对应询问的答案. 注意操作 2 的答案不需要进行取模.
Sample Input
Sample Input1
5
8 4 3 5 6
5
2 3 5
3 1 2
1 2 4 3
2 3 5
3 1 2
样例 2
见下发文件中的 ex_seg2.in/out.
Sample Output
Sample Output1
14
608
10
384
样例 1 解释
第三次操作后, 序列变为 [8, 0, 3, 1, 6].
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.
思路
修改只会让数变小, 每个数只会变小 log 次, 所以我们线段树维护区间或起来的值判断是否需要修改, 如果需要就暴力下去修改. 复杂度 O(nlog2n)
对于操作 3 直接把式子展开, 再维护一个区间平方和即可.
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 100010
#define ll long long
#define Ull unsigned long long
const ll P=998244353;
struct T
{
ll sqr,sum,orr;
};
T tree[N*4];
ll a[N];
int n,q;
T up(T x,T y)
{
T z;
z.orr=x.orr|y.orr;
z.sum=x.sum+y.sum;
z.sqr=(x.sqr+y.sqr)%P;
return z;
}
void build(int x,int l,int r)
{
if (l==r)
{
tree[x].sum=a[l];
tree[x].sqr=(a[l]%P*a[l]%P)%P;
tree[x].orr=a[l];
return;
}
int mid=(l+r)/2;
build(x+x,l,mid);
build(x+x+1,mid+1,r);
tree[x]=up(tree[x+x],tree[x+x+1]);
}
void change(int x,int l,int r,int s,int e,ll k)
{
int mid=(l+r)/2;
if (l==s && r==e)
{
if (l==r)
{
a[l]&=k;
tree[x].sum=a[l];
tree[x].sqr=(a[l]%P*a[l]%P)%P;
tree[x].orr=a[l];
return;
}
if ((tree[x+x].orr&k)!=tree[x+x].orr) change(x+x,l,mid,l,mid,k);
if ((tree[x+x+1].orr&k)!=tree[x+x+1].orr) change(x+x+1,mid+1,r,mid+1,r,k);
tree[x]=up(tree[x+x],tree[x+x+1]);
return;
}
if (e<=mid) {if ((tree[x+x].orr&k)!=tree[x+x].orr) change(x+x,l,mid,s,e,k);}
else
if (s>mid) {if ((tree[x+x+1].orr&k)!=tree[x+x+1].orr) change(x+x+1,mid+1,r,s,e,k);}
else
{
if ((tree[x+x].orr&k)!=tree[x+x].orr) change(x+x,l,mid,s,mid,k);
if ((tree[x+x+1].orr&k)!=tree[x+x+1].orr) change(x+x+1,mid+1,r,mid+1,e,k);
}
tree[x]=up(tree[x+x],tree[x+x+1]);
}
T find(int x,int l,int r,int s,int e)
{
if (l==s && r==e) return tree[x];
int mid=(l+r)/2;
if (e<=mid) return find(x+x,l,mid,s,e);
else if (s>mid) return find(x+x+1,mid+1,r,s,e);
else
{
T y=find(x+x,l,mid,s,mid);
T z=find(x+x+1,mid+1,r,mid+1,e);
return up(y,z);
}
}
int main()
{
freopen("seg.in","r",stdin);
freopen("seg.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
scanf("%d",&q);
ll tt,l,r;
ll k;
for (int i=1;i<=q;i++)
{
scanf("%lld%lld%lld",&tt,&l,&r);
if (tt==1)
{
scanf("%lld",&k);
change(1,1,n,l,r,k);
}
if (tt==2)
{
T s=find(1,1,n,l,r);
printf("%lld\n",s.sum);
}
if (tt==3)
{
T s=find(1,1,n,l,r);
printf("%lld\n",(2*(r-l+1)%P*s.sqr%P+2*(s.sum%P)%P*(s.sum%P)%P)%P);
}
}
return 0;
}