codeforces920f(线段树)

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 123 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 a1a2, ..., 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 SUM li ri (1 ≤ ti ≤ 21 ≤ li ≤ ri ≤ n).

There is at least one SUM query.

Output

For each SUM query print the answer to it.

Example
input
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
30
13
4
22

题意:给出一个数组,有两个操作,一个操作把区间所有数都变成其因子个数,另一个操作询问区间和。

思路:线段树。先预处理因子个数,并且需要注意如果线段树某一重复段一直更新,而一个数变为它因子数这个操作经过一定次数后,这个数不会再变化,这会是很大的浪费。通过预先计算得最大次数为6。节点中加一个更改次数的标志,大于一定数后就不在进行更新操作所以这样大大降低的时间。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define L(x) (x << 1)//左儿子
#define R(x) (x << 1 | 1)//右儿子
#define sz(x) (tree[x].r - tree[x].l + 1)//区间大小
#define maxm 1000005
using namespace std;
typedef long long ll;
const ll MAXN = 300005;
ll n,m,a,b,c,num[MAXN];
int yz[maxm];
int chge[maxm];
string t;
// l == 左;r == 右;p == now;
struct tree{
    ll l,r,sum,tim;//修改求和
}tree[MAXN << 2];

//标记下放们 p == now
void update(ll p){
    tree[p].sum = tree[L(p)].sum + tree[R(p)].sum;
}

//简单的建立
void build(ll l,ll r,ll p){
	tree[p].tim=0;
    tree[p].l = l,tree[p].r = r;
    if(l == r){
        tree[p].sum = num[l];
        return;
    }
    ll mid = (tree[p].l + tree[p].r) >> 1;
    build(l,mid,L(p));  build(mid + 1,r,R(p));
    update(p);
}

//区间修改
void change(ll l,ll r,ll p){
	if(tree[p].l>=l&&tree[p].r<=r)
	{
		if(tree[p].tim>=10)
			return;
		tree[p].tim++;
	}
	if(tree[p].l==tree[p].r)
	{
		tree[p].sum=yz[num[tree[p].l]];
		num[tree[p].l]=yz[num[tree[p].l]];
		return;
	}
    ll mid = (tree[p].l + tree[p].r) >> 1;
    if(l <= mid) change(l,r,L(p));
    if(mid < r) change(l,r,R(p));
    update(p);
}

//区间求和
ll ask_sum(ll l,ll r,ll p){
    if(l <= tree[p].l && tree[p].r <= r)
        return tree[p].sum;
    ll ans = 0,mid = (tree[p].l + tree[p].r) >> 1;
    if(l <= mid) ans += ask_sum(l,r,L(p));
    if(mid < r) ans += ask_sum(l,r,R(p));
    update(p);  return ans;
}

int YinZi(int n)
{
	int ans=1;
    for (int i=2;i*i<=n;i++)  
    {
        if (n%i==0)
		{
		   int num=0;
	        while(n%i==0)
			{
				num++;
				n=n/i;
			}
			ans*=(num+1);
		}
    }  
    if(n>1)
    	ans*=2; 
	return ans;
}
void init()
{
	memset(yz,0,sizeof(yz));
	for(int i=1;i<maxm;i++)
	{
		yz[i]=YinZi(i);
		chge[i]=yz[i]-i;
	}
}
/*
int maxx=0;
int dp[maxm];
void hh()
{
	dp[1]=0;
	dp[2]=0;
	dp[3]=1;
	for(int i=4;i<maxm;i++)
	{
		dp[i]=dp[yz[i]]+1;
		maxx=max(maxx,dp[i]);
	}
	cout<<maxx<<endl;
}
*/
int main()
{
	init();
//	hh();
	while(~scanf("%d%d",&n,&m))
	{
		memset(num,0,sizeof(num)); 
		for(int i=1;i<=n;i++)
		{
			scanf("%I64d",&num[i]);  
		}
		build(1,n,1);
		int op,l,r;
		while(m--)
		{
			scanf("%d%d%d",&op,&l,&r);
			if(op==1)
			{
				change(l,r,1);
			}
			else
			{
				printf("%I64d\n",ask_sum(l,r,1));
			}
		}
	}
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值