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 and , we say .
The pot is very special that it can make everyone awake immediately.
Now Little L provides () integers 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 by x ().
MAX l r : Calculate the value of
,
where p is prime.
Now you need to perform q() 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() and q(), 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.
样例输入
5 6 MULTIPLY 3 5 2 MULTIPLY 2 5 3 MAX 1 5 MULTIPLY 1 4 2 MULTIPLY 2 5 5 MAX 3 5
样例输出
ANSWER 1 ANSWER 2
样例解释
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 , and this is written as .
题目大意:
给定初始值为1的n个数,执行以下两种操作:
1、将 [l,r] 区间内的整数都乘以x
2、询问 [l,r] 区间内的一个极值,即
首先,理解一下
这其实是把 进行了整数的素数幂分解,而 求的是分解后各个素数的幂中最大次数。
于是, 也就好理解了,就是对某个区间求上述最大值的最大值。
要注意的是,这里的整数都是从1开始,通过乘上某些x得到的,而x的范围被规定为 [2,10],那么进行整数的素数幂分解后,出现的素数只可能是2、3、5、7,也就是说我们每次要求的实际上就是2、3、5、7的幂次中最大的那个。
由于涉及到区间更新和区间查询,我们可以对2、3、5、7分别构造线段树,记录每个区间内它们的最大幂次。
另外,要注意对2-10的每个数字,要根据他们的素因子去更新对应的树,比如6,就需要更新2、3对应的线段树。
具体解释见代码。
#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;
}