[线段树]小花梨的数组

题目描述
小花梨得到了一个长度为n的数组a,现在要对它进行三种操作:
⚫1 l r对所有的i∈[l,r],a[i]=a[i]∗minprime(a[i])
⚫2 l r对所有的i∈[l,r],a[i]=a[i]/minprime(a[i])
⚫3 x
求a[x]的值

现在给出初始数组a,对其进行m次操作,对于第三种操作输出结果。

 

输入
第一行输入两个正整数n,m,表示数组的长度以及操作次数(1≤n,m≤100000)
第二行输入n个正整数表示数组a(1≤ai≤1000000)
接下来m行表示m次操作,每行输入格式为"1 l r"或者"2 l r",或者"3 x",对应上述三种操作。1≤l,r,x≤n,l≤r

 

输出
对于第三种操作输出答案即可,答案对109+7进行取模。

 

样例输入

复制样例数据

5 8 
1 2 3 4 5 
1 2 4 
3 2 
3 3 
2 2 5 
3 2 
3 5 
1 5 5 
3 5 
样例输出
4
9
2
1
1

思路:线段树维护乘和除的次数;op==1时,乘的次数直接加1,op==2时,先抵消一个乘的次数,若乘全被抵消再给除的次数加1
#include<bits/stdc++.h>
#define mod 1000000007
typedef long long ll;
using namespace std;

int n,m,a[100010];//区间长度
struct Node{
  int l,r,sum,lazy;
}node_mul[100010*4],node_div[100010*4];//节点数=区间长度*4

void clearTree(Node node[]){
for(int i=1;i<=n;i++) node[i].sum=0,node[i].lazy=0;
}

void build(Node node[],int k,int l,int r){
  node[k].l=l,node[k].r=r;
  if(l==r) return;
  else{
    int mid=(l+r)>>1;
    build(node,2*k,l,mid);
    build(node,2*k+1,mid+1,r);
  }
}

void pushdown(Node node[],int f,int k){
  if(f==0){
    node[2*k].sum+=node[k].lazy*(node[2*k].r-node[2*k].l+1);
    node[2*k].lazy+=node[k].lazy;
    node[2*k+1].sum+=node[k].lazy*(node[2*k+1].r-node[2*k+1].l+1);
    node[2*k+1].lazy+=node[k].lazy;
    node[k].sum-=node[k].sum*(node[k].r-node[k].l+1);
    node[k].lazy=0;
  }
  else{
    if(node_mul[2*k].lazy>=node[k].lazy){
        node_mul[2*k].sum-=node[k].lazy*(node_mul[2*k].r-node_mul[2*k].l+1);
        node_mul[2*k].lazy-=node[k].lazy;
    }
    else{
        node[2*k].sum+=(node[k].lazy-node_mul[2*k].lazy)*(node[2*k].r-node[2*k].l+1);
        node[2*k].lazy+=(node[k].lazy-node_mul[2*k].lazy);
        node_mul[2*k].sum-=node_mul[2*k].lazy*(node_mul[2*k].r-node_mul[2*k].l+1);
        node_mul[2*k].lazy=0;
    }
    if(node_mul[2*k+1].lazy>=node[k].lazy){
        node_mul[2*k+1].sum-=node[k].lazy*(node_mul[2*k+1].r-node_mul[2*k+1].l+1);
        node_mul[2*k+1].lazy-=node[k].lazy;
    }
    else{
        node[2*k+1].sum+=(node[k].lazy-node_mul[2*k+1].lazy)*(node[2*k+1].r-node[2*k+1].l+1);
        node[2*k+1].lazy+=(node[k].lazy-node_mul[2*k+1].lazy);
        node_mul[2*k+1].sum-=node_mul[2*k+1].lazy*(node_mul[2*k+1].r-node_mul[2*k+1].l+1);
        node_mul[2*k+1].lazy=0;
    }
    node[k].sum-=node[k].sum*(node[k].r-node[k].l+1);
    node[k].lazy=0;
  }
}

int ask_point_val(Node node[],int f,int k,int x){
  if(x<=0) return 0;
  if(node[k].l==node[k].r) return node[k].sum;
  else{
    //push_down时先除后乘
    if(node_div[k].lazy) pushdown(node_div,1,k);
    if(node_mul[k].lazy) pushdown(node_mul,0,k);
    int mid=(node[k].l+node[k].r)>>1;
    if(x<=mid) return ask_point_val(node,f,2*k,x);
    else return ask_point_val(node,f,2*k+1,x);
  }
}

void addval_to_interval(Node node[],int f,int k,int l,int r){
  if(l<=node[k].l&&node[k].r<=r){
    if(f==0){
        node[k].sum+=1*(node[k].r-node[k].l+1);
        node[k].lazy+=1;
    }
    else{
        if(node_mul[k].lazy){//若有乘,先抵消
            node_mul[k].sum-=1*(node[k].r-node[k].l+1);
            node_mul[k].lazy-=1;
        }
        else{//若无乘,直接加1
            node[k].sum+=1*(node[k].r-node[k].l+1);
            node[k].lazy+=1;
        }
    }
  }
  else{
    //push_down时先除后乘
    if(node_div[k].lazy) pushdown(node_div,1,k);
    if(node_mul[k].lazy) pushdown(node_mul,0,k);
    int mid=(node[k].l+node[k].r)/2;
    if(l<=mid) addval_to_interval(node,f,2*k,l,r);
    if(r>mid) addval_to_interval(node,f,2*k+1,l,r);
    node[k].sum=node[2*k].sum+node[2*k+1].sum;
  }
}

vector<int> factor[100010];
void get_primefactor(int pos){
  int x=a[pos];
  if(x==1){
    factor[pos].push_back(1);
    return;
  }
  for(int i=2;i*i<=x;i++){
    if(x%i==0){
        while(x%i==0){
            factor[pos].push_back(i);
            x/=i;
        }
    }
  }
  if(x>1) factor[pos].push_back(x);
}

ll qpow(ll a,ll b){
  ll ret=1;
  while(b){
    if(b&1) ret=ret*a%mod;
    a=a*a%mod;
    b>>=1;
  }
  return ret;
}

int main()
{
    clearTree(node_mul);clearTree(node_div);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        get_primefactor(i);
    }
    build(node_mul,1,1,n);build(node_div,1,1,n);
    for(int i=1;i<=m;i++){
        int op;scanf("%d",&op);
        if(op==1){
            int l,r;scanf("%d%d",&l,&r);
            addval_to_interval(node_mul,0,1,l,r);
        }
        else if(op==2){
            int l,r;scanf("%d%d",&l,&r);
            addval_to_interval(node_div,1,1,l,r);
        }
        else{
            int x;scanf("%d",&x);
            int num_mul=ask_point_val(node_mul,0,1,x);
            int num_div=ask_point_val(node_div,1,1,x);
            //printf("add=%d sub=%d\n",num_mul,num_div);
            ll ans=1;
            int siz=factor[x].size();
            if(num_div<siz){
              int tmp=factor[x][num_div];
              for(int i=num_div;i<siz;i++) ans=ans*factor[x][i]%mod;
              ans=ans*qpow(tmp,num_mul)%mod;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}
View Code

转载于:https://www.cnblogs.com/lllxq/p/10914009.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值