Codeforces920F. SUM and REPLACE

F. SUM and REPLACE

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Let D(x) be the number of positive divisors of a positive integer x. For example, D(2) = 2 (2 is divisible by 1 and 2), D(6) = 4 (6 is divisible by 1, 2, 3 and 6).

You are given an array a of n integers. You have to process two types of queries:

  1. REPLACE l r — for every  replace ai with D(ai);
  2. SUM l r — calculate .

Print the answer for each SUM query.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 3·105) — the number of elements in the array and the number of queries to process, respectively.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 106) — the elements of the array.

Then m lines follow, each containing 3 integers tiliri denoting i-th query. If ti = 1, then i-th query is REPLACE li ri, otherwise it's SUMli ri (1 ≤ ti ≤ 2, 1 ≤ li ≤ ri ≤ n).

There is at least one SUM query.

Output

For each SUM query print the answer to it.

Example

input

Copy

7 6
6 4 1 10 3 2 4
2 1 7
2 4 5
1 3 5
2 4 4
1 5 7
2 1 7

output

Copy

30
13
4
22

线段树。开始求整除的个数  要用dp。先求出,其某个因子。

import java.util.*;
import java.io.*;

public class Main {
	public static void main(String args[]) {new Main().run();}

	FastReader in = new FastReader();
	PrintWriter out = new PrintWriter(System.out);
	void run(){
		work();
		out.flush();
	}
	long mod=998244353;
	long gcd(long a,long b) {
		return b==0?a:gcd(b,a%b);
	}
	int[] dp;
	void work() {
		int[] rec=new int[1000001];
		Arrays.fill(rec,1);
		for(int i=2;i*i<=1000000;i++) {
			if(rec[i]==1) {
				for(int j=i;j*i<=1000000;j++) {
					rec[i*j]=i;
				}
			}
		}
		dp=new int[1000001];
		dp[1]=1;
		for(int i=2;i<=1000000;i++) {
			int d=rec[i];
			if(d==1)dp[i]=2;
			else {
				int c=0;
				int num=i;
				while(num%d==0) {
					c++;
					num/=d;
				}
				dp[i]=dp[num]*(c+1);
			}
		}
		int n=in.nextInt(),m=in.nextInt();
		int[] A=new int[n];
		for(int i=0;i<n;i++)A[i]=in.nextInt();
		Node root=new Node();
		for(int i=0;i<n;i++) {
			insert(root,A[i],i,0,n-1);
		}
		for(int i=0;i<m;i++) {
			int type=in.nextInt();
			if(type==1) {
				update(root,in.nextInt()-1,in.nextInt()-1,0,n-1);
			}else {
				out.println(query(root,in.nextInt()-1,in.nextInt()-1,0,n-1));
			}
		}
	}
	
	private long query(Node node, int s, int e, int l, int r) {
		if(l>=s&&r<=e) {
			return node.sum;
		}
		Node lnode=getLnode(node);
		Node rnode=getRnode(node);
		long ret=0;
		int m=(l+r)/2;
		if(m>=s) {
			ret+=query(lnode,s,e,l,m);
		}
		if(m<e) {
			ret+=query(rnode,s,e,m+1,r);
		}
		return ret;
	}
	
	private void update(Node node,int s, int e,int l,int r) {
		if(l==r) {
			node.sum=dp[(int)node.sum];
			if(dp[(int)node.sum]==node.sum)node.cnt--;
			return;
		}
		Node lnode=getLnode(node);
		Node rnode=getRnode(node);
		int m=(l+r)/2;
		if(m>=s&&lnode.cnt>0) {
			update(lnode,s,e,l,m);
		}
		if(m<e&&rnode.cnt>0) {
			update(rnode,s,e,m+1,r);
		}
		node.sum=lnode.sum+rnode.sum;
		node.cnt=lnode.cnt+rnode.cnt;
	}
	
	private void insert(Node node, long v,int idx, int l, int r) {
		if(l==r) {
			node.sum=v;
			if(dp[(int)v]!=v)node.cnt++;
			return;
		}
		int m=(l+r)/2;
		Node lnode=getLnode(node);
		Node rnode=getRnode(node);
		if(idx<=m) {
			insert(lnode,v,idx,l,m);
		}else {
			insert(rnode,v,idx,m+1,r);
		}
		node.cnt=lnode.cnt+rnode.cnt;
		node.sum=lnode.sum+rnode.sum;
	}
	
	private Node getRnode(Node node) {
		if(node.rnode==null) node.rnode=new Node();
		return node.rnode;
	}
	
	private Node getLnode(Node node) {
		if(node.lnode==null) node.lnode=new Node();
		return node.lnode;
	}
	
	class Node{
		Node lnode,rnode;
		int cnt;
		long sum;
	}
}	



class FastReader
{
	BufferedReader br;
	StringTokenizer st;

	public FastReader()
	{
		br=new BufferedReader(new InputStreamReader(System.in));
	}

	public String next() 
	{
		if(st==null || !st.hasMoreElements())
		{
			try {
				st = new StringTokenizer(br.readLine());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return st.nextToken();
	}

	public int nextInt() 
	{
		return Integer.parseInt(next());
	}

	public long nextLong()
	{
		return Long.parseLong(next());
	}
}

预处理因数个数的时候 想复杂了。以下较简单方法。速度慢了点(951ms,上面701ms)。

import java.util.*;
import java.io.*;

public class Main {
	public static void main(String args[]) {new Main().run();}

	FastReader in = new FastReader();
	PrintWriter out = new PrintWriter(System.out);
	void run(){
		work();
		out.flush();
	}
	long mod=998244353;
	long gcd(long a,long b) {
		return b==0?a:gcd(b,a%b);
	}
	int[] dp;
	void work() {
		dp=new int[1000001];
		for(int i=1;i<=1000000;i++) {
			for(int j=i;j<=1000000;j+=i) {
				dp[j]++;
			}
		}
		int n=in.nextInt(),m=in.nextInt();
		int[] A=new int[n];
		for(int i=0;i<n;i++)A[i]=in.nextInt();
		Node root=new Node();
		for(int i=0;i<n;i++) {
			insert(root,A[i],i,0,n-1);
		}
		for(int i=0;i<m;i++) {
			int type=in.nextInt();
			if(type==1) {
				update(root,in.nextInt()-1,in.nextInt()-1,0,n-1);
			}else {
				out.println(query(root,in.nextInt()-1,in.nextInt()-1,0,n-1));
			}
		}
	}
	
	private long query(Node node, int s, int e, int l, int r) {
		if(l>=s&&r<=e) {
			return node.sum;
		}
		Node lnode=getLnode(node);
		Node rnode=getRnode(node);
		long ret=0;
		int m=(l+r)/2;
		if(m>=s) {
			ret+=query(lnode,s,e,l,m);
		}
		if(m<e) {
			ret+=query(rnode,s,e,m+1,r);
		}
		return ret;
	}
	
	private void update(Node node,int s, int e,int l,int r) {
		if(l==r) {
			node.sum=dp[(int)node.sum];
			if(dp[(int)node.sum]==node.sum)node.cnt--;
			return;
		}
		Node lnode=getLnode(node);
		Node rnode=getRnode(node);
		int m=(l+r)/2;
		if(m>=s&&lnode.cnt>0) {
			update(lnode,s,e,l,m);
		}
		if(m<e&&rnode.cnt>0) {
			update(rnode,s,e,m+1,r);
		}
		node.sum=lnode.sum+rnode.sum;
		node.cnt=lnode.cnt+rnode.cnt;
	}
	
	private void insert(Node node, long v,int idx, int l, int r) {
		if(l==r) {
			node.sum=v;
			if(dp[(int)v]!=v)node.cnt++;
			return;
		}
		int m=(l+r)/2;
		Node lnode=getLnode(node);
		Node rnode=getRnode(node);
		if(idx<=m) {
			insert(lnode,v,idx,l,m);
		}else {
			insert(rnode,v,idx,m+1,r);
		}
		node.cnt=lnode.cnt+rnode.cnt;
		node.sum=lnode.sum+rnode.sum;
	}
	
	private Node getRnode(Node node) {
		if(node.rnode==null) node.rnode=new Node();
		return node.rnode;
	}
	
	private Node getLnode(Node node) {
		if(node.lnode==null) node.lnode=new Node();
		return node.lnode;
	}
	
	class Node{
		Node lnode,rnode;
		int cnt;
		long sum;
	}
}	



class FastReader
{
	BufferedReader br;
	StringTokenizer st;

	public FastReader()
	{
		br=new BufferedReader(new InputStreamReader(System.in));
	}

	public String next() 
	{
		if(st==null || !st.hasMoreElements())
		{
			try {
				st = new StringTokenizer(br.readLine());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return st.nextToken();
	}

	public int nextInt() 
	{
		return Integer.parseInt(next());
	}

	public long nextLong()
	{
		return Long.parseLong(next());
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值