2019 ICPC Asian Regional Competition (Yinchuan Station) G Pot !! [Line segment tree interval modification + interval query]

Description

Little Q is very sleepy, and he really needs some coffee to make him awake. At this time, Little L brings a pot to Little Q, and he states the pot as follows.

For a prime number p, if p^m | n and p^{m+1}\not | n, we say \text{pot}_p(n)=m.

The pot is very special that it can make everyone awake immediately.

Now Little L provides (1 \ le n \ le 10 ^ 5) integers a_1, a_2, \cdots, a_n​ to Little Q, each of which is 1 initially. After that, Little L shows 2 types of queries:

  • MULTIPLY l r x : For every i∈[l,r] (1≤l≤r≤n), multiply a_i​ by x (2 \ le x \ le 10).

  • MAX l r : Calculate the value of

    \displaystyle \max_{l\le i\le r} \left\{ \max_{p|a_i} \left\{ \text{pot}_p (a_i) \right\} \right\}~(1 \le l \le r \le n),

     

where p is prime.

Now you need to perform q(1 \ le q \ le 10 ^ 5) queries of these two types of queries described above.

If you perform a “MULTIPLY” query, you don't need to output anything.

If you perform a “MAX” query, you need to output a line like ANSWER y, where y the value you've calculated.

Input 

The first line contains two integers n(1 \ le n \ le 10 ^ 5) and q(1 \ le q \ le 10 ^ 5), the number of integers and the number of queries.

Each of the next q lines contains one type of query described above.

Output

 For each “MAX” query, output one line in the format of ANSWER y, where y the value you have calculated.

Sample input

5 6
MULTIPLY 3 5 2
MULTIPLY 2 5 3
MAX 1 5
MULTIPLY 1 4 2 
MULTIPLY 2 5 5 
MAX 3 5

Sample output

ANSWER 1
ANSWER 2

Sample explanation

If m and n are non-zero integers, or more generally, non-zero elements of an integral domain, it is said that m divides n if there exists an integer k, or an element k of the integral domain, such that m \times k=n, and this is written as m \mid n.

 The main idea:

Given n numbers with an initial value of 1, perform the following two operations:

1. Multiply all integers in the [l, r] interval by x

2. Ask for an extreme value in the interval [l, r], namely                    

\displaystyle \max_{l\le i\le r} \left\{ \max_{p|a_i} \left\{ \text{pot}_p (a_i) \right\} \right\}~(1 \le l \le r \le n)

First, understand   \displaystyle \max_{p|a_i} \left\{ \text{pot}_p (a_i) \right\} \right\}

In fact, this is to a_ibe a prime integer powers of decomposition, while  \displaystyle \max_{p|a_i} \left\{ \text{pot}_p (a_i) \right\} \right\}  seeking the maximum number is a power of each prime number decomposition.

Therefore, \displaystyle \max_{l\le i\le r} \left\{ \max_{p|a_i} \left\{ \text{pot}_p (a_i) \right\} \right\}~(1 \le l \le r \le n)  it is easy to understand, that is, to find the maximum value of the maximum value for a certain interval.

It should be noted that the integers here start from 1 and are obtained by multiplying some x, and the range of x is specified as [2,10], then after the prime power decomposition of the integer, the prime numbers that appear are only possible It is 2,3,5,7, which means that each time we request is actually the largest of the powers of 2,3,5,7.

Since it involves interval updating and interval query, we can construct line segment trees for 2, 3, 5, 7 respectively, and record their maximum power in each interval.

In addition, it should be noted that for each number of 2-10, the corresponding tree should be updated according to their prime factors, such as 6, you need to update the line tree corresponding to 2, 3.

See the code for specific explanation.

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <cstdio> 
#include <map> 
#include <iomanip>
 
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
//#define INF 0x3f3f3f3f
 
using namespace std;
 
const int maxn=1e5+5;
const ll INF=0x3f3f3f3f3f3f3f3f;
 
struct segtree{
	int l,r; 
	ll maxx;
	ll tag; 	//延迟标记	
};
 
segtree t[5][maxn*4];//1对应素因子2的线段树,2--3,3--5,4--7
 
void pushup(int index,int p){//区间合并,向上拓展 
	t[index][p].maxx=max(t[index][2*p].maxx,t[index][2*p+1].maxx);
}
 
void pushdown(int index,int p){//将父节点的状态向下传递(延迟标记的传递) 
	if(t[index][p].tag){//说明父节点的状态已被改变 
		int lson=p*2,rson=p*2+1;
		int mid=(t[index][p].l+t[index][p].r)/2;
		t[index][lson].tag+=t[index][p].tag;		//注意这里一定是要累加,因为该区间有可能被父节点多次更新 
		t[index][rson].tag+=t[index][p].tag;
		t[index][lson].maxx+=t[index][p].tag;
		t[index][rson].maxx+=t[index][p].tag;
		t[index][p].tag=0;//父节点传递完成后标志复原 
	}
}
 
void build(int index,int p,int l,int r){//建树 
	int mid=(l+r)/2;
	t[index][p].l=l;
	t[index][p].r=r;
	t[index][p].tag=0;	
	t[index][p].maxx=0;
	if(l==r){
		return;
	}
	build(index,p*2,l,mid);
	build(index,2*p+1,mid+1,r);
	pushup(index,p);
}
 
ll query(int index,int p,int L,int R){
	if(L<=t[index][p].l&&R>=t[index][p].r){
		return t[index][p].maxx;
	}
    pushdown(index,p);//注意在向下查询前,要先下推
	int lson=p*2;
	int rson=p*2+1;
	ll tmax=-INF;
	int mid=(t[index][p].l+t[index][p].r)/2;
	if(L<=mid){		//如果左侧还有区间 
		tmax=max(tmax,query(index,lson,L,R));
	}
	if(R>mid){ 		//如果右侧还有区间
		tmax=max(tmax,query(index,rson,L,R));
	} 
	return tmax;
} 
 
 
 
void update(int index,int p,int L,int R,ll num){
	int lson=p*2,rson=p*2+1;
	if(L<=t[index][p].l&&R>=t[index][p].r){//区间被完全覆盖 
		t[index][p].tag+=num;		//这里累加,原因同上 
		t[index][p].maxx+=num;
		return;//由于此处直接返回,所以需要延迟标记,此处未更新该节点的子树 
	}
	pushdown(index,p);//进入子节点前先传递延迟标记,便于接下来的递归更新 
	int mid=(t[index][p].l+t[index][p].r)/2;
	if(L<=mid){
		update(index,lson,L,R,num);
	} 
	if(R>mid){
		update(index,rson,L,R,num);
	}
	pushup(index,p);//子节点更新返回后要更新父节点 
}
 
int main(){
	int n,q;
	scanf("%d%d",&n,&q);
	for(int i=1;i<=4;i++){
		build(i,1,1,n);
	} 
	char ch[20];
	for(int i=1;i<=q;i++){
		scanf("%s",ch);
		if(ch[1]=='U'){
			int a,b;
			ll c;
			scanf("%d%d%lld",&a,&b,&c);
            //处理2-10的每个数字,更新相应的树
			if(c==6){
				update(1,1,a,b,1);
				update(2,1,a,b,1);
			}
			else if(c==10){
				update(1,1,a,b,1);
				update(3,1,a,b,1);
			}
			else if(c%2==0){
				if(c==2){
					update(1,1,a,b,1);
				}
				else if(c==4){
					update(1,1,a,b,2);//4中包含2的2次幂,所以要加2
				}
				else{
					update(1,1,a,b,3);//8中包含2的3次幂,所以要加3
				}
			}
			else if(c%3==0){
				if(c==3){
					update(2,1,a,b,1);
				}
				else{
					update(2,1,a,b,2);//9中包含3的2次幂,所以要加2
				}
			}
			else if(c%5==0){
				update(3,1,a,b,1);
			}
			else{
				update(4,1,a,b,1);
			}
		}
		else{
			int a,b;
			scanf("%d%d",&a,&b);
			ll ans=-INF,tmp;
			for(int i=1;i<=4;i++){
				ans=max(ans,query(i,1,a,b));//依次比较取该区间中2、3、5、7的幂的最大值
			}
			printf("ANSWER %lld\n",ans);
		}
	} 
	return 0;
}

 

 

Published 30 original articles · won 5 · 900 views

Guess you like

Origin blog.csdn.net/qq_42840665/article/details/103430301