hdoj 5634 Rikka with Phi 【线段树 + 欧拉】

Rikka with Phi

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 207    Accepted Submission(s): 64


Problem Description
Rikka and Yuta are interested in Phi function (which is known as Euler's totient function).

Yuta gives Rikka an array  A[1..n]  of positive integers, then Yuta makes  m  queries. 

There are three types of queries: 

1lr  

Change  A[i]  into  φ(A[i]) , for all  i[l,r] .

2lrx  

Change  A[i]  into  x , for all  i[l,r] .

3lr  

Sum up  A[i] , for all  i[l,r] .

Help Rikka by computing the results of queries of type 3.

 

Input
The first line contains a number  T(T100)  ——The number of the testcases. And there are no more than 2 testcases with  n>105

For each testcase, the first line contains two numbers  n,m(n3×105,m3×105)

The second line contains  n  numbers  A[i]

Each of the next  m  lines contains the description of the query. 

It is guaranteed that  1A[i]107  At any moment.
 

Output
For each query of type 3, print one number which represents the answer.
 

Sample Input
  
  
1 10 10 56 90 33 70 91 69 41 22 77 45 1 3 9 1 1 10 3 3 8 2 5 6 74 1 1 8 3 1 9 1 2 10 1 4 9 2 8 8 69 3 3 9
 

Sample Output
  
  
80 122 86
 

题意:给你n个数和m次操作。

1 x y 表示将区间[x, y]里面的数变为自己的欧拉函数。

2 x y v 表示将区间[x, y]里面的数修改为v。

3 x y 表示求区间[x, y]的和。


思路:n<=10^7的数,最多进行logn次欧拉函数求解就会变成1。

对于操作2,可以直接区间更新。

对于操作1,我们标记 每个区间是否满足直接区间更新的条件——条件为左、右子区间的所有数全部相等。若某一个区间满足条件,可以用一个变量记录当前区间的元素值。这样在更新时,没必要直接更新到底。初始显然只有叶子区间,之后每次两个子区间改变,我们都需要将信息向上传递。


AC代码:


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
const int MAXN = 3*1e5+1;
const int MAXM = 1e7+1;
LL euler[MAXM];
void Geteuler()
{
    memset(euler, 0, sizeof(euler));
    euler[1] = 1;
    for(LL i = 2; i < MAXM; i++) if(!euler[i])
        for(LL j = i; j < MAXM; j += i){
            if(!euler[j]) euler[j] = j;
            euler[j] = euler[j] / i * (i-1);
        }
}
struct Tree{
    int l, r, len; LL sum, lazy;
};
Tree tree[MAXN<<2];
void PushUp(int o){
    tree[o].sum = tree[ll].sum + tree[rr].sum;
    if(tree[ll].lazy == tree[rr].lazy) tree[o].lazy = tree[ll].lazy;
    else tree[o].lazy = 0;
}
void PushDown(int o)
{
    if(tree[o].lazy)
    {
        tree[ll].lazy = tree[rr].lazy = tree[o].lazy;
        tree[ll].sum = tree[o].lazy * tree[ll].len;
        tree[rr].sum = tree[o].lazy * tree[rr].len;
    }
}
void Build(int o, int l, int r)
{
    tree[o].l = l; tree[o].r = r;
    tree[o].len = r - l + 1;
    if(l == r)
    {
        scanf("%lld", &tree[o].sum);
        tree[o].lazy = tree[o].sum;
        return ;
    }
    int mid = (l + r) >> 1;
    Build(ll, l, mid); Build(rr, mid+1, r);
    PushUp(o);
}
void Update1(int o, int L, int R)
{
    if(tree[o].lazy && L == tree[o].l && R == tree[o].r)
    {
        tree[o].sum = euler[tree[o].lazy] * tree[o].len;
        tree[o].lazy = euler[tree[o].lazy];
        return ;
    }
    PushDown(o);
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(R <= mid) Update1(ll, L, R);
    else if(L > mid) Update1(rr, L, R);
    else { Update1(ll, L, mid); Update1(rr, mid+1, R); }
    PushUp(o);
}
void Update2(int o, int L, int R, int v)
{
    if(L == tree[o].l && R == tree[o].r)
    {
        tree[o].lazy = v;
        tree[o].sum = 1LL * v * tree[o].len;
        return ;
    }
    PushDown(o);
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(R <= mid) Update2(ll, L, R, v);
    else if(L > mid) Update2(rr, L, R, v);
    else { Update2(ll, L, mid, v); Update2(rr, mid+1, R, v); }
    PushUp(o);
}
LL Query(int o, int L, int R)
{
    if(L == tree[o].l && R == tree[o].r)
        return tree[o].sum;
    PushDown(o);
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(R <= mid) return Query(ll, L, R);
    else if(L > mid) return Query(rr, L, R);
    else return Query(ll, L, mid) + Query(rr, mid+1, R);
}
int main()
{
    Geteuler();
    int t; scanf("%d", &t);
    while(t--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        Build(1, 1, n);
        while(m--)
        {
            int op, x, y, v;
            scanf("%d%d%d", &op, &x, &y);
            if(op == 1) Update1(1, x, y);
            else if(op == 2) {scanf("%d", &v); Update2(1, x, y, v);}
            else if(op == 3) printf("%lld\n", Query(1, x, y));
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值