LightOJ 1135 Count the Multiples of 3(线段树+懒标记)

1135 - Count the Multiples of 3
Time Limit: 3 second(s)Memory Limit: 64 MB

You have an array with n elements which is indexed from 0 to n - 1. Initially all elements are zero. Now you have to deal with two types of operations

1.      Increase the numbers between indices i and j (inclusive) by 1. This is represented by the command '0 i j'.

2.      Answer how many numbers between indices i and j (inclusive) are divisible by 3. This is represented by the command '1 i j'.

Input

Input starts with an integer T (≤ 5), denoting the number of test cases.

Each case starts with a line containing two integers n (1 ≤ n ≤ 105) and q (1 ≤ q ≤ 50000) denoting the number of queries. Each query will be either in the form '0 i j' or '1 i j' where ij are integers and 0 ≤ i ≤ j < n.

Output

For each case, print the case number first. Then for each query in the form '1 i j', print the desired result.

Sample Input

Output for Sample Input

1

10 9

0 0 9

0 3 7

0 1 4

1 1 7

0 2 2

1 2 4

1 8 8

0 5 8

1 6 9

Case 1:

2

3

0

2

Note

Dataset is huge, use faster i/o methods.


SPECIAL THANKS: JANE ALAM JAN (DESCRIPTION, SOLUTION, DATASET)

题意:0-n-1的数,m次操作,每次有0往区间添加1,和1,询问区间能被3整除的数字个数输出。

思路:之前一直卡TLE。线段树更新区间的话,要用懒标记法,不然会TLE。第一次写有点搓。每个结点存放mod为0,mod为1,mod为2的数字个数,和一个标记v。如果加一,就是把3个数字换一下。

代码:

#include <stdio.h>
#include <string.h>
#define max(a,b) ((a)>(b)?(a):(b))
const int N = 1000005;

int t, n, Q;
struct Tree {
	int l, r, mod0, mod1, mod2, v;
}st[N];

void build(int l, int r, int id) {
	if (l != r) {
		int mid = (l + r) / 2;
		build(l, mid, 2 * id);
		build(mid + 1, r, 2 * id + 1);
	}
	st[id].l = l; st[id].r = r; 
	if (l == r)
		st[id].mod0 = 1;
	else
		st[id].mod0 = st[id * 2].mod0 + st[id * 2 + 1].mod0;
	st[id].mod1 = st[id].mod2 = st[id].v = 0;
}

void tra(Tree &t) {
	int t0 = t.mod0, t1 = t.mod1, t2 = t.mod2;
	t.mod0 = t2; t.mod1 = t0; t.mod2 = t1;
}

void Insert(int l, int r, int id) {
	if (l == st[id].l && r == st[id].r) {
		tra(st[id]);
		st[id].v++;
		return;
	}
	if (st[id].v) {
		int t = st[id].v;
		st[id].v = 0;
		st[id * 2].v += t;
		st[id * 2 + 1].v += t;
		t %= 3;
		while (t--) {
			tra(st[id * 2]);
			tra(st[id * 2 + 1]);
		}
	}
	int mid = (st[id].l + st[id].r) / 2;
	if (l <= mid && r > mid) {
		Insert(l, mid, id * 2);
		Insert(mid + 1, r, id * 2 + 1);
	}
	else if (r <= mid) Insert(l, r, id * 2);
	else Insert(l, r, id * 2 + 1);
	st[id].mod0 = st[id * 2].mod0 + st[id * 2 + 1].mod0;
	st[id].mod1 = st[id * 2].mod1 + st[id * 2 + 1].mod1;
	st[id].mod2 = st[id * 2].mod2 + st[id * 2 + 1].mod2;
} 

int Query(int l, int r, int id) {
	if (l == st[id].l && r == st[id].r) {
		return st[id].mod0;
	}
	if (st[id].v) {
		int t = st[id].v;
		st[id].v = 0;
		st[id * 2].v += t;
		st[id * 2 + 1].v += t;
		t %= 3;
		while (t--) {
			tra(st[id * 2]);
			tra(st[id * 2 + 1]);
		}
	}
	int mid = (st[id].l + st[id].r) / 2;
	if (l <= mid && r > mid) {
		return Query(l, mid, id * 2) + Query(mid + 1, r, id * 2 + 1);
	}
	else if (r <= mid) return Query(l, r, id * 2);
	else return Query(l, r, id * 2 + 1);
}

void init() {
	memset(st, 0, sizeof(st));
	scanf("%d%d", &n, &Q);
	build(0, n - 1, 1);
}

void solve() {
	int a, b, c;
	while (Q--) {
		scanf("%d%d%d", &a, &b, &c);
		if (a == 0)
			Insert(b, c, 1);
		else
			printf("%d\n", Query(b, c, 1));
	}
}

int main() {
	int cas = 0;
	scanf("%d", &t);
	while (t--) {
		printf("Case %d:\n", ++cas);
		init();
		solve();
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sigma函数是指一个数字的所有因子之和。给定一个数字n,需要求出有多少个数字的Sigma函数是偶数。\[2\] 为了解决这个问题,可以先筛选出n范围内的素数(范围在10^6即可),然后对n进行素因子分解。对于每个因子,如果它的Sigma函数中连乘的每一项都是偶数,那么整个Sigma函数就是偶数。具体实现中,可以判断每个因子的平方根是否为偶数,如果是偶数,则减去(平方根+1)/2。\[1\] 另外,还可以使用O(1)的做法来解决这个问题。根据观察,所有的完全平方数及其两倍的值都会导致Sigma函数为偶数。因此,可以直接计算n的平方根,然后减去(平方根+1)/2即可得到结果。\[3\] #### 引用[.reference_title] - *1* [Sigma Function](https://blog.csdn.net/PNAN222/article/details/50938232)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【LightOJ1336】Sigma Function(数论)](https://blog.csdn.net/qq_30974369/article/details/79009498)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值