题目链接:点击打开链接
题意:有3种区间操作, 1是把区间内的所有数变成它的欧拉函数值, 2是把区间所有数都变成一个数x,3是查询区间和。
思路:后两个操作就是线段树的区间修改和求和, 没什么好说的。
题解说用平衡树(弱不会), 不过大致思路线段树同样可以维护, 因为一个数进行最多phiO(logn)次就会变成1, 所以我们可以在递归结束,向上传标记的时候顺便看看其子区间是不是都等于1, 是就合并起来, 给这个点重新标记。
细节参见代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef long double ld;
const ld EPS = 1e-9, PI = 3.1415926535897932384626433832795;
const int mod = 1000000000 + 7;
const int INF = int(1e9);
const ll INF64 = ll(1e18);
const int maxn = 300000 + 10;
int T, n, m, v, id, l, r, x;
ll sum[maxn<<2], setv[maxn<<2];
#define Max 10000010
ll euler[Max] = {0};
void Init(){
euler[1]=1;
for(ll i=2;i<Max;i++)
euler[i]=i;
for(ll i=2;i<Max;i++)
if(euler[i]==i)
for(ll j=i;j<Max;j+=i)
euler[j]=euler[j]/i*(i-1);
}
void PushUp(int o) {
sum[o] = sum[o<<1] + sum[o<<1|1];
if(setv[o<<1] == setv[o<<1|1]) setv[o] = setv[o<<1];
else setv[o] = 0;
}
void build(int l, int r, int o) {
int m = (l + r) >> 1;
sum[o] = 0;
setv[o] = 0;
if(l == r) {
scanf("%d",&v);
sum[o] = setv[o] = v;
return ;
}
build(l, m, o<<1);
build(m+1, r, o<<1|1);
PushUp(o);
}
void pushdown(int l, int r, int o) {
if(setv[o]) {
int m = (l + r) >> 1;
setv[o<<1] = setv[o<<1|1] = setv[o];
sum[o<<1] = (ll)(m - l + 1) * setv[o];
sum[o<<1|1] = (ll)(r - m) * setv[o];
setv[o] = 0;
}
}
void update(int L, int R, int v, int l, int r, int o) {
int m = (l + r) >> 1;
if(L <= l && r <= R) {
setv[o] = (ll)v;
sum[o] = (ll)v * (r - l + 1);
return ;
}
pushdown(l, r, o);
if(L <= m) update(L, R, v, l, m, o<<1);
if(m < R) update(L, R, v, m+1, r, o<<1|1);
PushUp(o);
}
void haha(int L, int R, int l, int r, int o) {
int m = (l + r) >> 1;
if(setv[o] && L <= l && r <= R) {
setv[o] = euler[setv[o]];
sum[o] = setv[o] * (r - l + 1);
return ;
}
if(l == r) return ;
pushdown(l, r, o);
if(L <= m) haha(L, R, l, m, o<<1);
if(m < R) haha(L, R, m+1, r, o<<1|1);
PushUp(o);
}
ll query(int L, int R, int l, int r, int o) {
int m = (l + r) >> 1;
if(L <= l && r <= R) {
return sum[o];
}
pushdown(l, r, o);
ll ans = 0;
if(L <= m) ans += query(L, R, l, m, o<<1);
if(m < R) ans += query(L, R, m+1, r, o<<1|1);
PushUp(o);
return ans;
}
int main() {
Init();
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
build(1, n, 1);
while(m--) {
scanf("%d%d%d",&id,&l,&r);
if(id == 1) haha(l, r, 1, n, 1);
else if(id == 2) {
scanf("%d",&x);
update(l, r, x, 1, n, 1);
}
else printf("%I64d\n",query(l, r, 1, n, 1));
}
}
return 0;
}