woj1464

Problem 1464 - Deal with numbers

Time Limit: 5000MS      Memory Limit: 65536KB      
Total Submit: 209      Accepted: 21      Special Judge: No  

Description

    There are n numbers with the corresponding NO.1-n, and the value of the i-th number is xi. 

Define three operations:

    1.Division a b c, in the interval [a,b], if the value of a number is equal or greater than zero, then its value changed to it divide C(integer division). (1 <= a <= b <= n, 1 <= c <= 50000)

    2.Minus a b c, all numbers in the interval [a, b] subtract c. (1 <= a <= b <= n ,1<= c <= 50000) 

    3.Sum a b, query for the sum of all numbers in the interval [a, b]. (1 <= a <= b <= n)

Input

    Input contains several test cases.
    The first line is an integer T indicates the number of test cases.
    For each test case, the first line contains two integer numbers n and m (1<=n,m<=10^5), indicates the number of numbers and the number of operations. The second line contains n integers, the i-th integer shows the original value of the i-th number (1<=xi<=50000). Then m lines followed, each line shows an operation.

Output

    For each set of data, output the case number in a line first, and then for each query, output an integer in a line to show the answer.
    Print a blank line after the end of each test cases.

Sample Input

2
5 5
1 2 3 4 5
Division 1 3 2
Minus 3 5 3
Sum 1 2
Sum 3 4
Sum 5 5
5 3
-2 -1 3 -2 1
Sum 1 2
Division 1 2 2
Sum 1 2

Sample Output

Case 1:
1
-1
2

Case 2:
-3
-3

 
#include<cstdio>
#include<cstring>
using namespace std;
#define N 100005
#define ll long long
ll left[4*N],right[4*N];
ll sum[4*N],add[4*N];
bool f[4*N];
inline void push_up(ll k)
{
    sum[k]=sum[2*k]+sum[2*k+1];
    f[k]=f[2*k]&&f[2*k+1];
}
void push_down(ll k,ll l)
{
    if(add[k]!=0)
    {
        add[2*k]+=add[k];add[2*k+1]+=add[k];
        sum[2*k]+=add[k]*(l-l/2);sum[2*k+1]+=add[k]*(l/2);
        add[k]=0;
    }
}
void build(ll l,ll r,ll k)
{
    add[k]=sum[k]=0;
    left[k]=l;
    right[k]=r;
    if(l==r)
    {
        scanf("%lld",&sum[k]);
        f[k]=(sum[k]<0);
        return ;
    }
    ll mid=(l+r)>>1;
    build(l,mid,2*k);
    build(mid+1,r,2*k+1);
    push_up(k);

}
ll l,r,c;
void div(ll k)
{
    if(f[k])return;
    if(left[k]==right[k])
    {
        if(sum[k]>=0&&c)sum[k]/=c;
        f[k]=sum[k]<0;
        return ;
    }
    push_down(k,right[k]-left[k]+1);
    ll mid=(left[k]+right[k])>>1;
    if(l<=mid)div(2*k);
    if(r>mid)div(2*k+1);
    push_up(k);
}
void ADD(ll k)
{
    if(l<=left[k]&&right[k]<=r)
    {
        add[k]+=c;
        sum[k]+=c*(right[k]-left[k]+1);
        return ;
    }
    push_down(k,right[k]-left[k]+1);
    ll mid=(left[k]+right[k])>>1;
    if(l<=mid)ADD(2*k);
    if(r>mid)ADD(2*k+1);
    push_up(k);
}
ll SUM(ll k)
{
    if(l<=left[k]&&right[k]<=r)
    {
        return sum[k];
    }
    push_down(k,right[k]-left[k]+1);
    ll mid=(left[k]+right[k])>>1;
    ll ans=0;
    if(l<=mid)ans+=SUM(2*k);
    if(r>mid)ans+=SUM(2*k+1);
    return ans;
}
int main()
{
    //freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
    freopen("G:\\新建文件夹\\D\\D.in","r",stdin);
    freopen("G:\\新建文件夹\\D\\ddd.out","w",stdout);
    ll n,m,t;
    char s[20];
    scanf("%lld",&t);
    {
        int k=0;
        while(~scanf("%lld%lld",&n,&m))
        {
            printf("Case %d:\n",++k);
            build(1,n,1);
            while(m--)
            {
                scanf("%s%lld%lld",s,&l,&r);
                if(s[0]=='S')
                {
                    printf("%lld\n",SUM(1));
                }
                else
                {
                    scanf("%lld",&c);
                    if(s[0]=='D')
                    {
                        if(c!=1)div(1);//没有这个优化过不了
                    }
                    else if(s[0]=='M')
                    {
                        c=-c;
                        ADD(1);
                    }
                }
            }
            puts("");
        }
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值