问题描述
小葱喜欢除法,所以他给了你N个数a1, a2, ⋯, aN,并且希望你执行M次操作,每次操作可能有以下两种:
给你三个数l, r, v,你需要将al, al+1, ⋯, ar之间所有v的倍数除以v。
给你两个数l, r,你需要回答al + al+1 + ⋯ + ar的值是多少。
输入格式
第一行两个整数N, M,代表数的个数和操作的次数。
接下来一行N个整数,代表N个数一开始的值。
输出格式
对于每一次的第二种操作,输出一行代表这次操作所询问的值。
样例输入
5 3
1 2 3 4 5
2 1 5
1 1 3 2
2 1 5
- 1
- 2
- 3
- 4
- 5
样例输出
15
14
- 1
- 2
评测用例规模与约定
对于30%的评测用例,1 ≤ N, M ≤ 1000;
对于另外20%的评测用例,第一种操作中一定有l = r;
对于另外20%的评测用例,第一种操作中一定有l = 1 , r = N;
对于100%的评测用例,1 ≤ N, M ≤ 105,0 ≤ a1, a2, ⋯, aN ≤ 106, 1 ≤ v ≤ 106, 1 ≤ l ≤ r ≤ N。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();//n个数
int[] nums = new int[N+1];
long[] treeSum = new long[N+1];
int m = scanner.nextInt();//m次操作
for (int i = 1; i <=N; i++) {
nums[i] = scanner.nextInt();
add(treeSum,i,nums[i]);//构造树状数组
}
for (int i = 0; i < m; i++) {
int option = scanner.nextInt();
if (option==1){
int L =scanner.nextInt();
int r =scanner.nextInt();
int v =scanner.nextInt();
if (v!=1){//特别重要,没有这个判断会超时,只能得50分
for (int j = L; j <=r; j++) {
if(nums[j]>=v && nums[j]%v==0){
int value = nums[j] -nums[j]/v;
nums[j] = nums[j]/v;
add(treeSum,j,-value);
}
}
}
}else if(option==2){
int L = scanner.nextInt();
int r = scanner.nextInt();
long count = getSum(treeSum,r)-getSum(treeSum,L-1);
System.out.println(count);
}
}
}
private static long getSum(long[] treeNums, int n) {
long sum = 0 ;
while (n>0){
sum += treeNums[n];
n -=lowbit(n);
}
return sum;
}
private static void add(long[] treeNums, int index,int value) {
if (index>0){
for (int i = index; i<=treeNums.length-1 ; i+=lowbit(i)) {
treeNums[i] +=value;
}
}
}
private static int lowbit(int value) {//lowbit(i) = 2^k
return value & (-value);
}
}