HDU 5634 Rikka with Phi

题意:有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;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值