题意:有3种区间操作, 1是把区间内的所有数变成它的欧拉函数值, 2是把区间所有数都变成一个数x,3是查询区间和。
题解 : 一眼看过去就是线段树问题,对于这一类问题,无论是给一个区间取对数,还是给一个区间开根号,或者是取欧拉函数值,由于这一类函数收敛的非常快,可以严格logn内收敛到1然后到1我们就可以不再进行更新,这样我们就可以暴力更新每个点的欧拉函数值,用线段树维护区间和和区间最大值,维护区间和是为了查询,维护最大值是为了当最大值为1的时候我们就不向下更新欧拉函数值,(如果一个区间被打上标记我们也不用向下更新,直接把标记改成标记的欧拉函数值即可)。
数据量太大用 cin 会超时 有些地方会乘爆int。
code :
#include <algorithm>
#include <cstring>
#include <cstdio>
#define ll long long
using namespace std;
const int maxn = 3e5 + 10;
const int N = 1e7 + 10;
struct node {
ll l,r;
ll sum;
ll lazy;
ll mx;
}tr[maxn << 3];
int a[maxn] = {0};
ll phi[N] = {0};
void build (int l,int r,int root) {
tr[root].l = l;
tr[root].r = r;
tr[root].lazy = 0;
if (l == r) {
tr[root].sum = tr[root].mx = a[l];
return;
}
int mid = (l + r) >> 1;
build(l, mid, root << 1);
build(mid + 1, r, root << 1 | 1);
tr[root].sum = tr[root << 1].sum + tr[root << 1 | 1].sum;
tr[root].mx = max(tr[root << 1].mx,tr[root << 1 | 1].mx);
}
void pushdown (int root) {
ll len = tr[root].r - tr[root].l + 1;
tr[root << 1].lazy = tr[root].lazy;
tr[root << 1 | 1].lazy = tr[root].lazy;
tr[root << 1].sum = (tr[root].lazy) * ((len + 1)/(ll)2);
tr[root << 1 | 1].sum = tr[root].lazy * ((len) / (ll)2);
tr[root << 1].mx = tr[root].lazy;
tr[root << 1 | 1].mx = tr[root].lazy;
tr[root].sum = tr[root << 1].sum + tr[root << 1 | 1].sum;
tr[root].mx = max(tr[root << 1].mx,tr[root << 1 | 1].mx);
tr[root].lazy = 0;
return ;
}
void update1 (int l,int r,int root) {
if (tr[root].l == tr[root].r) {
if (tr[root].l >= l && tr[root].r <= r) {
tr[root].sum = phi[tr[root].sum];
tr[root].mx = tr[root].sum;
tr[root].lazy = 0;
}
return ;
}
if (tr[root].l >= l && tr[root].r <= r && tr[root].lazy) {
tr[root].lazy = phi[tr[root].lazy];
tr[root].sum = (tr[root].r - tr[root].l + 1) * tr[root].lazy;
return ;
}
if (tr[root].lazy) pushdown(root);
ll mid = (tr[root].l + tr[root].r) >> 1;
if (l > mid) {
if (tr[root << 1 | 1].mx != 1)
update1(l, r, root << 1 | 1);
}
else if (r <= mid) {
if (tr[root << 1].mx != 1)
update1(l, r, root << 1);
}
else {
if (tr[root << 1].mx != 1)
update1(l, r, root << 1);
if (tr[root << 1 | 1].mx != 1)
update1(l, r, root << 1 | 1);
}
tr[root].sum = tr[root << 1].sum + tr[root << 1 | 1].sum;
tr[root].mx = max (tr[root << 1].mx,tr[root << 1 | 1].mx);
}
void update2 (int l,int r,int root,ll val) {
if (tr[root].l >= l && tr[root].r <= r) {
tr[root].lazy = val;
tr[root].mx = val;
tr[root].sum = (tr[root].r - tr[root].l + 1) * val;
return ;
}
if (tr[root].lazy) pushdown(root);
ll mid = (tr[root].l + tr[root].r) >> 1;
if (l > mid) update2(l, r, root << 1 | 1,val);
else if (r <= mid) update2(l, r, root << 1, val);
else {
update2(l, r, root << 1 | 1,val);
update2(l, r, root << 1, val);
}
tr[root].mx = max (tr[root << 1].mx,tr[root << 1 | 1].mx);
tr[root].sum = tr[root << 1].sum + tr[root << 1 | 1].sum;
}
ll query (int l,int r,int root) {
if (tr[root].l >= l && tr[root].r <= r) {
return tr[root].sum;
}
if (tr[root].lazy) pushdown(root);
ll mid = (tr[root].l + tr[root].r) >> 1;
if (l > mid) return query(l, r, root << 1 | 1);
else if (r <= mid) return query(l, r, root << 1);
else {
return query(l, r, root << 1) + query(l, r, root << 1 | 1);
}
}
int main () {
phi[1] = 1;
for (ll i = 2;i <= 1e7 + 5; ++ i) {
if (!phi[i]) {
phi[i] = i - 1;
for (ll j = i + i;j <= 1e7 + 5;j += i) {
if (!phi[j]){
phi[j] = j;
}
phi[j] = phi[j] / i * (i - 1);
}
}
}
int T;
scanf ("%d",&T);
while (T--) {
int n,m;
scanf ("%d%d",&n,&m);
for (int i = 1;i <= n; ++ i) scanf ("%d",&a[i]);
build(1, n, 1);
for (int i = 0;i < m; ++ i) {
int c;
scanf ("%d",&c);
if (c == 1) {
int l,r;
scanf ("%d%d",&l,&r);
update1(l, r, 1);
}
else if (c == 2) {
int l,r;
ll val;
scanf ("%d%d%lld",&l,&r,&val);
update2(l, r, 1, val);
}
else {
int l,r;
scanf ("%d%d",&l,&r);
printf ("%lld\n",query(l, r, 1));
}
}
}
return 0;
}