[line segment tree] [interval LCM] forced on-line repair interval LCM

Keywords: Algorithm

Description

Give a length of   n   Sequence of   a. Need to execute   m   Operations:

-1   x   y: Let a[x]=y

- 2   l   r: Answer interval [l,r]   LCM, more specifically, output LCM(a[l],a[l+1],... a[r − 1],a[r])

LCM(x,y)   by   x   and   y   Minimum common multiple of, e.g. LCM(12,15)=60

Since the result may be too large, you only need to output the answer pair 998244353   The results after taking the mold.

Input

The first line gives two positive integers n,m ≤ 10 ^ 5, representing the length of the sequence and the number of operations, respectively.

The second line gives   n   Positive integers a[i] ≤ 100, separated by spaces, with spaces at the end of the line.

behind   m   Each line gives three numbers Op   x   y   Used to describe operations, where op ∈ {1,2}, x,y ≤ 109. Because this problem is forced to be online, all parameters need to be recalculated:

-Operation   1: x=(x+last)modn+1,y=(y+last)mod100+1

-Operation   2: l=(x+last)modn+1,r=(y+last)modn+1. If l > R   Exchange them.

last   For the last operation   two   Your answer, initially   last=0

Output

For each operation   two   The output line represents the answer

Sample Input 1 

4 5
2 3 5 7
2 123 321
2 456 654
1 1111 1111
2 2222 2222
2 3333 3333

Sample Output 1

105
105
7
17

Hint

Example:

The five operations are:

- 2 2 4

- 2 2 4

- 1 1 17

- 2 4 4

- 2 1 1

Question meaning: given a group of numbers, there are two operations at the same time, one is single point update, and the other is the minimum common multiple of query interval.

Analysis: it looks like maintaining the interval gcd, but it is actually different. The value of the interval gcd must be less than or equal to the maximum value in the interval, so there is no need to take the module in the process, and the interval lcm may be very large. It is necessary to take the module in the maintenance of the segment tree, that is, the lcm of each node needs to save the value after the module is taken, otherwise it will exceed the long long range, but an error will occur when the module is taken, After all, lcm(a, b)%c is not equal to lcm(a%c, b%c)%c. The positive solution is to consider the meaning of taking lcm for two numbers. The essence of lcm for two numbers is to decompose the prime factors respectively, then take the maximum power of each prime factor and multiply it to be lcm, because gcd is to take the minimum power of each prime factor, and then use a*b/gcd to get lcm, that is, the remaining maximum power. Since the number in the sequence is at most 100 and there can be at most 25 quality factors, it is sufficient to build a segment tree for each quality factor and maintain the maximum power of the interval. In query, multiplying the maximum power of each quality factor in the interval is the answer.

The specific codes are as follows:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define mod 998244353
using namespace std;
//Unlike interval gcd, interval lcm may be very large and cannot be modeled in the process, so it cannot be solved in the same way as interval gcd 
//The essence of two numbers lcm is to decompose the prime factors separately, and then take the maximum power of each prime factor and multiply it to be lcm
//Because gcd is to take the minimum power of each quality factor, and then use a*b/gcd to get lcm, that is, the remaining maximum power 
//Since the number in the sequence is up to 100 and can have up to 25 prime numbers, it is sufficient to build a segment tree for each prime number and maintain the maximum value of the power interval
//lcm(a, b)%c!= lcm(a%c, b%c)%c, for example, a=7, b=9, c=5 
int n, m, _max[25][400020], a[25][100005]; 
int prime[25] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};

void push_up(int id, int cnt)
{
	_max[cnt][id] = max(_max[cnt][id<<1], _max[cnt][id<<1|1]);
}

void build(int l, int r, int id, int cnt)
{
	if(l == r)
	{
		_max[cnt][id] = a[cnt][l];
		return;
	}
	int m = l+r>>1;
	build(l, m, id<<1, cnt), build(m+1, r, id<<1|1, cnt);
	push_up(id, cnt);
}

void update(int L, int C, int l, int r, int id, int cnt)
{
	if(l == r)
	{
		_max[cnt][id] = C;
		return;
	}
	int m = l+r>>1;
	if(L <= m)
		update(L, C, l, m, id<<1, cnt);
	else
		update(L, C, m+1, r, id<<1|1, cnt);
	push_up(id, cnt);
}

int query(int L, int R, int l, int r, int id, int cnt)
{
	if(l == L && r == R)
		return _max[cnt][id];
	int m = l+r>>1;
	if(m >= R)
		return query(L, R, l, m, id<<1, cnt);
	else if(m+1 <= L)
		return query(L, R, m+1, r, id<<1|1, cnt);
	else
		return max(query(L, m, l, m, id<<1, cnt), query(m+1, R, m+1, r, id<<1|1, cnt));
}

signed main()
{
	cin >> n >> m;
	int t;
	for(int i = 1; i <= n; i++)
	{
		scanf("%d", &t);
		for(int j = 0; j < 25; j++)
			while(t%prime[j] == 0)
			{
				a[j][i]++;
				t /= prime[j];
			}
	}
	for(int i = 0; i < 25; i++)
		build(1, n, 1, i);
	int op, x, y;
	int last = 0;//Record the last output answer 
	for(int i = 1; i <= m; i++)
	{
		scanf("%d%d%d", &op, &x, &y);
		if(op == 1)
		{
			int L = (x+last)%n+1, C = (y+last)%100+1; 
			for(int j = 0; j < 25; j++)
			{
				int c = 0;
				while(C%prime[j] == 0)
				{
					c++;
					C /= prime[j];
				}
				update(L, c, 1, n, 1, j);
			}
		}
		else
		{
			int t1 = (x+last)%n+1, t2 = (y+last)%n+1;
			int l = min(t1, t2), r = max(t1, t2);
			long long ans = 1;
			for(int j = 0; j < 25; j++)
			{
				int t = query(l, r, 1, n, 1, j);
				ans = (ans*(long long)pow(prime[j], t))%mod;
			}
			last = ans;
			printf("%lld\n", ans);
		}
	}
    return 0;
}

Posted by tamilmani on Fri, 17 Sep 2021 07:44:48 -0700