您的位置:首页 > 其它

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

2016-02-27 23:38 316 查看


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(T≤100) ——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(n≤3×105,m≤3×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 1≤A[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: