hdu5634 BestCoder Round #73 (div.1)

 

Rikka with Phi

 
 Accepts: 5
 
 Submissions: 66
 Time Limit: 16000/8000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
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]A[1..n] of positive integers, then Yuta makes mm queries.

There are three types of queries:

1 \; l \; r1lr

Change A[i]A[i] into \varphi(A[i])φ(A[i]), for all i \in [l, r]i[l,r].

2 \; l \; r \; x2lrx

Change A[i]A[i] into xx, for all i \in [l, r]i[l,r].

3 \; l \; r3lr

Sum up A[i]A[i], for all i \in [l, r]i[l,r].

Help Rikka by computing the results of queries of type 3.

Input

The first line contains a number T(T \leq 100)T(T100) ——The number of the testcases. And there are no more than 2 testcases with n > 10 ^ 5n>105

For each testcase, the first line contains two numbers n,m(n \leq 3 \times 10^5, m \leq 3 \times 10^5)n,m(n3×105,m3×105)

The second line contains nn numbers A[i]A[i]

Each of the next mm lines contains the description of the query.

It is guaranteed that 1 \leq A[i] \leq 10^71A[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

 

/*
BestCoder Round #73 (div.1)
hdu5634	Rikka with Phi
本来最开始用伸展树(主要是线段树不是很熟)的,但是中间有点问题,导致一直是TLE,于是乎
就去写线段树了
感觉对线段树的理解上有很多问题TAT
思路:先打个表然后用线段树(平衡树)去解决
主要是有same标记,sum和,欧拉
中间在将一个区间改变成欧拉时,如果中间遇到了区间的same,直接
修改这个标记就好的
hhh-2016-02-25 17:54:59
*/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
using namespace std;
typedef long long ll;
typedef long double ld;

const int maxn = 300010;
ll euler[10000010] = {0};
void getEuler()
{
    euler[1] = 1;
    for(ll i =2 ; i <= 10000000; i++)
    {
        if(!euler[i])
        {
            for(ll j = i; j <= 10000000; j += i)
            {
                if(!euler[j])
                    euler[j] = j;
                euler[j] = euler[j]/i*(i-1);
            }
        }
    }
}

struct node
{
    int l,r;
    ll sum,same;
} segtree[maxn<<2];

void push_up(int r)
{
    int lson = r<<1,rson = (r<<1)|1;
    segtree[r].sum = segtree[lson].sum + segtree[rson].sum;
    if(segtree[lson].same == segtree[rson].same)
        segtree[r].same = segtree[lson].same;
    else
        segtree[r].same = 0;
}

void build(int i ,int l,int r)
{
    segtree[i].l = l,segtree[i].r = r;
    segtree[i].sum = segtree[i].same = 0;
    if(l == r)
    {
        scanf("%I64d",&segtree[i].same);
        segtree[i].sum = segtree[i].same;
        return ;
    }
    int mid = (l+r)>>1;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
    push_up(i);
}


void push_down(int r)
{
    int lson = r<<1,rson = (r<<1)|1;
    if(segtree[r].same)
    {
        segtree[lson].same = segtree[r].same;
        segtree[rson].same = segtree[r].same;
        segtree[lson].sum = (ll)(segtree[lson].r - segtree[lson].l+1)*segtree[r].same;
        segtree[rson].sum = (ll)(segtree[rson].r - segtree[rson].l+1)*segtree[r].same;
        segtree[r].same = 0;
    }
}

void make_euler(int i,int l,int r)
{
    //区间修改
    if(segtree[i].r <= r && segtree[i].l >= l && segtree[i].same)
    {
        segtree[i].same  = (ll)euler[segtree[i].same];
        segtree[i].sum = segtree[i].same*(ll)(segtree[i].r-segtree[i].l+1);
        return;
    }
    if(l == r) return ;
    int mid = (segtree[i].r +segtree[i].l) >>1;
    push_down(i);
    if(l <= mid)
        make_euler(i<<1,l,r);
    if(r > mid)
        make_euler((i<<1)|1,l,r);
    push_up(i);
}
void make_same(int i,int l,int r,ll c)
{
    if(segtree[i].r <= r && segtree[i].l >= l)
    {
        segtree[i].same = c;
        segtree[i].sum = segtree[i].same*(ll)(segtree[i].r-segtree[i].l+1);
        return;
    }
    int mid = (segtree[i].r +segtree[i].l) >>1;
    push_down(i);
    if(l <= mid)
        make_same(i<<1,l,r,c);
    if(r > mid)
        make_same((i<<1)|1,l,r,c);
    push_up(i);
}

ll get_sum(int i,int l,int r)
{
    int mid = (segtree[i].l + segtree[i].r) >> 1;
    if(segtree[i].l >= l && segtree[i].r <= r)
    {
        return segtree[i].sum;
    }
    push_down(i);
    ll ans = 0;
    if(l <= mid) ans += get_sum(i<<1,l,r);
    if(r > mid) ans += get_sum(i<<1|1,l,r);
    push_up(i);
    return ans;
}

int main()
{
    int T,n,m;
    getEuler();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        build(1,1,n);
        for(int i =1; i <= m; i++)
        {
            int op,l,r;
            ll c;
            scanf("%d",&op);
            if(op == 1)
            {
                scanf("%d%d",&l,&r);
                make_euler(1,l,r);
                //debug();
            }
            else if(op == 2)
            {
                scanf("%d%d%I64d",&l,&r,&c);
                make_same(1,l,r,c);
                // debug();
            }
            else if(op == 3)
            {
                scanf("%d%d",&l,&r);
                printf("%I64d\n",get_sum(1,l,r));
            }
        }
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/Przz/p/5409617.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值