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

1135 - Count the Multiples of 3
PDF (English) Statistics Forum
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;
}


你可能感兴趣的:(LightOJ 1135 Count the Multiples of 3(线段树+懒标记))