“卓见杯”2020年河南省第二届CCPC大学生程序设计竞赛 J.二进制与、平方和

2699: 二进制与、平方和

时间限制: 3 Sec  内存限制: 512 MB
提交: 58  解决: 10
[状态] [讨论版] [提交] [命题人:admin]

题目描述

请你维护一个长度为 n 的非负整数序列 a1,a2,…,an,支持以下两种操作:

  1. 第一种操作会将序列 al,al+1,…,ar 中的每个元素,修改为各自和 x 的"二进制与"(Bitwise binary AND)的值,其中 l,r,x 在每次操作时会给定;
  2. 第二种操作会询问序列 al,al+1,…,ar 中所有元素的平方和模 998244353的值,即 ∑i=lrai2 模 998244353,其中 l,r在每次操作时会给定。

总共有 q 次操作,请你在维护序列的过程中,输出第二种操作所询问的答案。注意需要取模。

输入

第一行,一个整数 n (1≤n≤3×105),表示序列的长度。
第二行,共 n 个整数 ai (0≤ai<224),表示序列。
第三行,一个整数 q (1≤q≤3×105),表示询问的数量。
接下来 q 行,每行表示一个操作,输入有两种格式:

  1. 第一种操作的格式为 "1 l r x",表示将序列中编号在区间  [l,r]  的所有元素,修改为和 x 二进制与操作后的值,其中  1≤l≤r≤n, 0≤x<224;
  2. 第二种操作的格式为 "2 l r",表示询问序列中编号在区间  [l,r]  的所有元素的平方和,模  998244353 的值,其中  1≤l≤r≤n。

数据保证至少有一个第二种操作,即保证至少询问一次答案。

输出

每当遇到第二种操作时,输出询问的答案。注意需要取模。

样例输入 Copy

3
13 31 28
4
2 1 3
1 3 3 25
1 1 2 18
2 2 3

样例输出 Copy

1914
900

提示

样例输入二
5
9 11 12 5 1
7
2 1 3
1 3 3 0
1 1 3 9
1 4 5 13
2 1 3
1 4 5 14
2 1 5


样例输出二
346
162
178


样例输入三
4
16777215 16777215 16777215 16777214
4
2 2 2
1 1 4 16777214
2 1 4
2 3 4


样例输出三
981185168
795789897
897017125


"二进制与"(Bitwise binary AND)结果的第 i 个二进制位为 1,当且仅当两个操作数的第 i 位都为 1。

思路:

开一颗线段树,然后维护每个区间各个位上的0跟1的个数,考虑对于每个位置最多被修改24次,因为一共

24位,如果当前为0后就不会再被修改了,如果当前位是1且与他AND的数字该位为1则也不需要修改。所以

直接暴力更新叶子节点,递归的时候判断当前区间有没有向下递归的意义了,没有直接return。有意义就是说

向下的子树中至少有一个点的值会被修改。不怎么写数据结构,此题时间复杂度不是很会证明。。

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
typedef long long ll;
int a[N];
int c[4 * N];
int cnt[4 * N][24];
int lzy[4 * N];
#define ls ((x) << 1)
#define rs ((x) << 1 | 1)
#define mid ((L) + (R) >> 1)
void push_up(int x)
{
	c[x] = (c[ls] + c[rs]) % mod;
	for (int i = 0; i < 24; i++)
		cnt[x][i] = cnt[ls][i] + cnt[rs][i];
}
void build(int x, int L, int R)
{
	if (L == R)
	{
		for (int i = 0; i < 24; i++)
			cnt[x][i] = ((a[L] >> i) & 1);
		c[x] = 1LL * a[L] * a[L] % mod;
		return;
	}
	build(ls, L, mid);
	build(rs, mid + 1, R);
	push_up(x);
}
void update(int x, int L, int R, int ql, int qr, int val)
{
	if (ql > qr)
		return;
	if (L == R)
	{
		int sum = 0;
		for (int i = 0; i < 24; i++)
		{
			if (((val >> i) & 1 == 1) && cnt[x][i])
				sum |= (1 << i);
			else
				cnt[x][i] = 0;
		}
		c[x] = 1LL * sum * sum % mod;
		return;
	}
	if (ql <= L && qr >= R)
	{
		int flag = 1;
		for (int i = 0; i < 24; i++)
		{
			if (cnt[x][i] && ((val >> i) & 1) == 0)
			{
				flag = 0;
				break;
			}
		}
		if (flag)
			return;
	}
	if (ql <= mid)
		update(ls, L, mid, ql, qr, val);
	if (qr > mid)
		update(rs, mid + 1, R, ql, qr, val);
	push_up(x);
}
int query(int x, int L, int R, int ql, int qr)
{
	if (ql <= L && qr >= R)
		return c[x];
	ll res = 0;
	if (ql <= mid)
		res += query(ls, L, mid, ql, qr), res %= mod;
	if (qr > mid)
		res += query(rs, mid + 1, R, ql, qr), res %= mod;
	return res;
}

int main()
{
#ifdef LOCAL
	freopen("E:/input.txt", "r", stdin);
#endif
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	build(1, 1, n);
	int q;
	scanf("%d", &q);
	while (q--)
	{
		int op;
		scanf("%d", &op);
		if (op == 1)
		{
			int L, R, x;
			scanf("%d%d%d", &L, &R, &x); 
			update(1, 1, n, L, R, x);
		}
		else
		{
			int L, R;
			scanf("%d%d", &L, &R);
			printf("%d\n", query(1, 1, n, L, R));
		}
	}
	return 0;
}

 

 

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值