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

来源:互联网 发布:word表格数据求和 编辑:程序博客网 时间:2024/06/11 04:58

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
110 1056 90 33 70 91 69 41 22 77 451 3 91 1 103 3 82 5 6 741 1 83 1 91 2 101 4 92 8 8 693 3 9
 

Sample Output
8012286
 

题意:给你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|1using 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 0
原创粉丝点击