HDU 5634 Rikka with Phi

题目大意:给一个序列,支持区间求 phi、区间赋值、区间求和。

\(n,m\leq 3* 10^5,A_i\leq10^7\)

线段树直接暴力。

一个数在不断变成它的欧拉函数若干次之后恒为一,且许多数的欧拉函数值都是相同的。这样的话,如果我们将修改操作进行改进,只有在当前区间在询问区间以内且当前区间中的数都相同时,我们才对这个区间进行修改,否则我们继续对其的左右儿子进行修改。

#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const int inf = 1e9 + 9;
const int N = 3e5 + 5;
const int M = 10000000 + 5;
using namespace std;
inline int read() {
	int s = 0,w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-')
			w = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * w;
}
using namespace std;
LL phi[M],pn[M];
bool vis[M];
int n,m,a[N],tot;
void init(){
    phi[1] = 1;
    for(int i = 2;i <= M - 5;i++){
        if(!vis[i]) pn[++tot] = i,phi[i] = i - 1;
        for(int j = 1;j <= tot;++j){
            if(i * pn[j] > M - 5)break;
            vis[i * pn[j]] = 1;
            if(i % pn[j] == 0){
                phi[i * pn[j]] = phi[i] * pn[j];
                break;
            }
            phi[i * pn[j]] = phi[i] * (pn[j] - 1);
        }
    }
}
namespace Segment{
	struct node{
		int l,r;
		LL sum,num;
	}t[N<<2];
	#define ls (k<<1)
	#define rs (k<<1|1)
	#define mid (t[k].l + t[k].r>>1)
	void pushup(int k){
	    t[k].sum = t[ls].sum + t[rs].sum;
	    t[k].num = t[ls].num == t[rs].num ? t[ls].num : 0;
	}
	void pushnow(int k,LL v){
	    t[k].num = v;
	    t[k].sum = v * (t[k].r - t[k].l + 1);
	}
	void pushdown(int k){
	    if(!t[k].num) return;
	    pushnow(ls,t[k].num),pushnow(rs,t[k].num);
	}
	void build(int k,int l,int r){
	    t[k].l = l,t[k].r = r;
	    if(l == r){
	        t[k].num = t[k].sum = a[l];
	        return;
	    }
	    build(ls,l,mid);
	    build(rs,mid + 1,r);
	    pushup(k);
	}
	void modify(int k,int l,int r){
	    if(r < t[k].l || t[k].r < l) return;
	    if(l <= t[k].l && t[k].r <= r && t[k].num){
	        pushnow(k,phi[t[k].num]);
	        return;
	    }
	    pushdown(k);
	    if(r <= mid) modify(ls,l,r);
	    else if(l > mid) modify(rs,l,r);
	    else modify(ls,l,mid),modify(rs,mid + 1,r);
	    pushup(k);
	}
	void update(int k,int l,int r,LL v){
	    if(r < t[k].l || t[k].r < l) return;
	    if(l <= t[k].l && t[k].r <= r){
	        pushnow(k,v);
	        return;
	    }
	    pushdown(k);
	    if(r <= mid) update(ls,l,r,v);
	    else if(l > mid) update(rs,l,r,v);
	    else update(ls,l,mid,v),update(rs,mid+1,r,v);
	    pushup(k);
	}
	inline LL query(int k,int l,int r){
	    if(r < t[k].l || t[k].r < l) return 0;
	    if(l <= t[k].l && t[k].r <= r) return t[k].sum;
	    pushdown(k);
	    if(r <= mid) return query(ls,l,r);
	    if(l > mid) return query(rs,l,r);
	    return query(ls,l,mid) + query(rs,mid+1,r);
	}
}
using namespace Segment;
void pre(){
	memset(t,0,sizeof(t));
    n = read(),m = read();
    for(int i = 1;i <= n;i++) a[i] = read();
    build(1,1,n);
    return ;
}
void solve(){
	int op = read(),l = read(),r = read();
    if(op == 1) modify(1,l,r);
    if(op == 2){
        LL v = read();
        update(1,l,r,v);
    }
    if(op == 3) printf("%lld\n",query(1,l,r));
    return ;
}
int main(){
    init();
    int T = read();
    while(T--){
        pre();
        while(m--) solve();
    }
    return 0;
}
posted @ 2020-03-03 20:55  优秀的渣渣禹  阅读(180)  评论(0编辑  收藏  举报