HDU 5634 Rikka with Phi

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] of positive integers, then Yuta makes m queries.  

There are three types of queries: 

1lr 

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

2lrx 

Change A[i] into x, for all i[l,r].

3lr 

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

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

 
Input
The first line contains a number T(T100) ——The number of the testcases. And there are no more than 2 testcases with n>105

For each testcase, the first line contains two numbers n,m(n3×105,m3×105)

The second line contains n numbers A[i]

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

It is guaranteed that 1A[i]107 At any moment.
 
Output
For each query of type 3, print one number which represents the answer.
 
改段求段,用线段树解决,首先预处理好欧拉函数
#include <iostream>
#include <cstring>
#include <cstdio>
typedef long long LL;
using namespace std;

const int N = 10000001;
#define SIZE 300005
LL p[N]; // phi(N)
LL a[SIZE],st[SIZE * 4 + 5],n,m;
LL changed[SIZE * 4 + 5];
int T;
LL Left(LL i){
  return 2*i;
}
LL Right(LL i){
  return 2*i+1;
}

void Build_Tree(LL i,LL l,LL r){
  // cout << l << r << endl;
  changed[i] = 0; st[i] = 0;
  if (l == r){
    LL v;
    scanf("%lld",&v);
    st[i] = v;
    changed[i] = v;
  }
  else {
    LL mid = l + (r-l) / 2;
    Build_Tree(Left(i),l,mid);
    Build_Tree(Right(i),mid+1,r);
    st[i] = st[Left(i)] + st[Right(i)];
  }
}

void Push_Up(LL i){
  st[i] = st[Left(i)] + st[Right(i)];
  if (changed[Left(i)] == changed[Right(i)])
    changed[i] =changed[Left(i)];
  else
    changed[i] = 0;
}

void Push_Down(LL i,LL l,LL r){
  if (changed[i]){
    LL c = changed[i];
    changed[Left(i)] = c;
    changed[Right(i)] = c;
    LL mid = l + (r-l) / 2;
    st[Left(i)] = (mid-l+1) * c;
    st[Right(i)] = (r-mid) * c;
    changed[i] = 0;
  }
}

void UpdateE(LL i,LL l,LL r,LL ql,LL qr){
  if (changed[i] && ql <= l && qr >= r){
    changed[i] = p[changed[i]];
    st[i] = (r-l+1) * changed[i];
    return;
  }
  LL mid = l + (r - l) / 2;
  if (l == r) return;
  Push_Down(i,l,r);
  if (ql <= mid) UpdateE(Left(i),l,mid,ql,qr);
  if (qr >= mid + 1) UpdateE(Right(i),mid+1,r,ql,qr);
  Push_Up(i);
}
void Update(LL i,LL l,LL r,LL ql,LL qr,LL c){ //ql、qr为需要更新的区间左右端点,addv为需要变更的值
  if (ql <= l && qr >= r) { //与单点更新一样,当当前结点被需要更新的区间覆盖时
    changed[i] = c;
    st[i] = (r-l+1) * c;
    return;
  }
  Push_Down(i,l,r);
  LL mid = l + (r-l) / 2;
  if (ql <= mid) Update(Left(i),l,mid,ql,qr,c);
  if (qr >= mid + 1) Update(Right(i),mid+1,r,ql,qr,c);
  Push_Up(i);
}

LL Query(LL i,LL l,LL r,LL ql,LL qr){ // 含义同上
  if (ql <= l && qr >= r) return st[i];
  Push_Down(i,l,r);
  LL mid = l + (r-l) / 2,ans = 0;
  if (ql <= mid) ans += Query(Left(i),l,mid,ql,qr);
  if (qr >= mid + 1) ans += Query(Right(i),mid+1,r,ql,qr);
  return ans;
}

void phi()
{
    for(int i=1; i<N; i++)  p[i] = i;
    for(int i=2; i<N; i+=2) p[i] >>= 1;
    for(int i=3; i<N; i+=2)
    {
        if(p[i] == i)
        {
            for(int j=i; j<N; j+=i)
                p[j] = p[j] - p[j] / i;
        }
    }
}


int main(){
  // freopen("test.in","r",stdin);
  // ios::sync_with_stdio(false);
  phi();
  scanf("%d",&T);
  for (int times = 1; times <= T; times ++){
    scanf("%lld %lld",&n,&m);
    Build_Tree(1,1,n);
    for (int i=1;i<=m;i++){
      int l,r,order;
      scanf("%d %d %d",&order,&l,&r);
      LL X;
      switch (order) {
        case 1:
          UpdateE(1,1,n,l,r);
          // for (int j=1;j<=25;j++){
          //   cout << st[j] << " ";
          // }
          // cout << endl;
          break;
        case 2:
          scanf("%lld",&X);
          Update(1,1,n,l,r,X);
          break;
        case 3:
          printf("%lld
",Query(1,1,n,l,r));
          break;
      }
    }
  }
  return 0;
}
View Code
原文地址:https://www.cnblogs.com/ToTOrz/p/7399911.html