wust1593线段树

题目大意:给你n个数,m次操作,操作有两种 0 l r ,计算n个数从l乘到r后置0的个数,1 a b ,将a位置换位b。每个数均小于100,n,m< 100000.

思路:简单的线段树,每个节点维护该区间拥有的2的因子个数,5的因子个数,以及数据里是否拥有0.

每次计算,如果有0输出1,否则输出因子2和5的最小个数。

ps:记录0的个数的时候没有0忘记初始化为0.。。。。。。。


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>

using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define maxn 200005
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define ULL long long
const long long INF=0x3fffffff;

int arr[maxn];
int n , m;
int num_tree;
struct tree
{
    int left , right ;
    int num2 , num5 , num0;
}ST[3*maxn];

int get2(int n)
{
    int ans = 0;
    while(n % 2 == 0 && n)
    {
        n /= 2;
        ans ++;
    }
    return ans;
}

int get5(int n)
{
    int ans = 0;
    while(n % 5 == 0 && n)
    {
        n /= 5;
        ans ++;
    }
    return ans;
}

void Build(int root , int left , int right)
{
    ST[root].left = left;
    ST[root].right = right;
    if(left == right)
    {
        ST[root].num2 = get2(arr[left]);
        ST[root].num5 = get5(arr[left]);
        if(arr[left] == 0) ST[root].num0 = 1;
        else ST[root].num0 = 0;
        return ;
    }
    int mid = (left + right) / 2;
    Build(2 * root , left , mid);
    Build(2 * root + 1 , mid + 1 , right);
    ST[root].num0 = ST[root*2].num0 + ST[2*root + 1].num0;
    ST[root].num2 = ST[root*2].num2 + ST[2*root + 1].num2;
    ST[root].num5 = ST[root*2].num5 + ST[2*root + 1].num5;
}

void update(int root ,int pos , int val)
{
    if(pos < ST[root].left || pos > ST[root].right) return ;
    int mid = (ST[root].right + ST[root].left) / 2;
    if(pos == ST[root].left && pos == ST[root].right)
    {
        ST[root].num2 = get2( val );
        ST[root].num5 = get5( val );
        if(val == 0) ST[root].num0 = 1;
        else ST[root].num0 = 0;
        return ;
    }
    if(pos <= mid) update(2*root , pos , val);
    else update(2 * root + 1 , pos ,val);
    ST[root].num0 = ST[root*2].num0 + ST[2*root + 1].num0;
    ST[root].num2 = ST[root*2].num2 + ST[2*root + 1].num2;
    ST[root].num5 = ST[root*2].num5 + ST[2*root + 1].num5;
}

int Query(int l , int r , int pos , int flag)
{
    if(ST[pos].left > r || ST[pos].right < l)
    {
          return 0 ;
    }
    int temp = (ST[pos].right + ST[pos].left) / 2;
    if(ST[pos].left == l && ST[pos].right == r)
    {
        if(flag == 0) return ST[pos].num0;
        else if(flag == 2) return ST[pos].num2;
        else return ST[pos].num5;
    }

    else if(r <= temp)
        return Query(l , r , 2 * pos , flag);
    else if(l > temp)
        return Query(l , r , 2 * pos + 1 , flag);
    else if(l <= temp && r > temp)
        return Query(l , temp , 2 * pos , flag) + Query(temp + 1, r , 2 * pos + 1 , flag);
}

int main()
{
    while(scanf("%d %d" , &n , &m) != EOF)
    {
        for(int i = 1 ; i <= n ; i++)
        {
            scanf("%d" , &arr[i]);
        }
        if(n == 0 ) continue;
        Build(1 , 1 , n);
        int a , b , c;
        for(int i = 0 ; i < m ; i ++ )
        {
            scanf("%d %d %d" , &a , &b , &c);
            if(a)
            {
                update(1 , b , c);
            }
            else
            {
                if(b > c) swap(b , c);
                if(Query(b , c , 1 , 0))
                    printf("1\n");
                else
                    printf("%d\n" , min(Query(b , c , 1 , 2 ) , Query(b , c , 1 , 5) ) );
            }
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值