zoukankan      html  css  js  c++  java
  • Naive Operations

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6315

    学习博客:https://blog.csdn.net/SunMoonVocano/article/details/81207676

    Naive Operations

    Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 502768/502768 K (Java/Others)
    Total Submission(s): 4002    Accepted Submission(s): 1773


    Problem Description
    In a galaxy far, far away, there are two integer sequence a and b of length n.
    b is a static permutation of 1 to n. Initially a is filled with zeroes.
    There are two kind of operations:
    1. add l r: add one for al,al+1...ar
    2. query l r: query ri=lai/bi
     
    Input
    There are multiple test cases, please read till the end of input file.
    For each test case, in the first line, two integers n,q, representing the length of a,b and the number of queries.
    In the second line, n integers separated by spaces, representing permutation b.
    In the following q lines, each line is either in the form 'add l r' or 'query l r', representing an operation.
    1n,q1000001lrn, there're no more than 5 test cases.
     
    Output
    Output the answer for each 'query', each one line.
     
    Sample Input
    5 12 1 5 2 4 3 add 1 4 query 1 4 add 2 5 query 2 5 add 3 5 query 1 5 add 2 4 query 1 4 add 2 5 query 2 5 add 2 2 query 1 5
     
    Sample Output
    1 1 2 4 4 6
     
    Source
     
    Recommend
    chendu   |   We have carefully selected several similar problems for you:  6460 6459 6458 6457 6456 
     
    题目大意:第一行输入n,p  代表数组a[]和b[]的长度为n ,p代表有p次操作,第二行n个数代表b[1]····b[n] 的值 a[1]···a[n]刚开始为0
    接下来p行代表p个操作
    add l r  表示区间   [l,r]内a数组每个数加一,
    query l r  输出区间lr内 ai/bi的值的和(ai/bi向下取整)
    思路:自己并不会做这道题,看了别人题解将近花了一天才做出来,感慨自己还是不熟悉线段树 ,一个小问题卡了两个多小时 ,代码中会说我卡在哪了,真的难受,。。。
    好了吗,下面真的说思路:
    因为ai/bi是向下取整,所以更新ai的值未必会影响到ai/bi的值 ,那么我们怎么进行区间更新呢?  说实话,想了挺久的,也没有想出来,正常思维下  给一个区间里每一个数加上1除以不同的数,那岂不是
    要遍历才知道是否超过1,什么情况下可以不用遍历就知道呢?  可以试着猜想一下,如果我们知道那个区间bi的最小值,那么如果区间内最小值都不能提供一个1,那么肯定其它的也是不行的
    重点来了:  与其给ai加上1 不如给bi减去一个1  每一次更新,只要bi大于1  那么肯定是对ai/bi没有影响的,所以只要bi-1就行了
    具体看代码:
    #include<iostream>
    #include<vector>
    #include<queue>
    #include<string.h>
    #include<cstring>
    #include<stdio.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+5;
    const int maxm=1000+5;
    ll b[maxn<<2];//b数组
    ll lazy[maxn<<2];//延迟标记
    ll sum[maxn<<2];//记录区间ai/bi的和
    ll mi[maxn<<2];//记录b数组区间最小值
    ll ans=0;
    void Pushup(ll rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);//存区间最小的值
    }
    void Build(ll l,ll r,ll rt)
    {
        if(l==r)
        {
            mi[rt]=b[l];
            //cout<<"rt:"<<rt<<"mi:"<<mi[rt]<<endl;
            return ;
        }
        ll mid=(l+r)>>1;
        Build(l,mid,rt<<1);
        Build(mid+1,r,rt<<1|1);
        Pushup(rt);
    }
    void Pushdown(ll rt)
    {
        mi[rt<<1]-=lazy[rt];
        mi[rt<<1|1]-=lazy[rt];
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
    void Updata(ll l ,ll r,ll rt,ll L,ll R)//(1,n,1,l,r)
    {
        //cout<<"*"<<"l:"<<l<<"r:"<<r<<"L:"<<L<<"R:"<<R<<"mi:"<<mi[rt]<<"rt:"<<rt<<endl;
        if(L<=l&&r<=R)//这里是重点 
        {
    //        cout<<"叶子rt:"<<rt<<endl;
            if(mi[rt]>1)//最小的都大于1,那么整个区间ai/bi肯定是没有影响的,
            {
                mi[rt]--;
                lazy[rt]++;
                return ;
            }
        }
    
        if(l==r)//到了叶子节点,代表mi[rt]<=1  此时sum值要加1,同时mi[rt]恢复原值
        {
            sum[rt]++;
            mi[rt]=b[l];
            return ;
        }
        if(lazy[rt])
            Pushdown(rt);
        ll mid=(l+r)>>1;
    
    
        if(L<=mid) Updata(l,mid,rt<<1,L,R);
        if(R>mid) Updata(mid+1,r,rt<<1|1,L,R);
    
        Pushup(rt);
    }
    void Query(ll l,ll r,ll rt,ll L,ll R)
    {
        if(L<=l&&r<=R)
        {
            ans+=sum[rt];
            return ;
        }
        ll mid=(l+r)>>1;
    
        if(lazy[rt])
            Pushdown(rt);
    
        if(L<=mid) Query(l,mid,rt<<1,L,R);//就是这里卡了几个小时 我把l写成1了  !!!  一直re  找了很久。。。
        if(R>mid) Query(mid+1,r,rt<<1|1,L,R);
    
    }
    int main()
    {
        ll n,q;
        ll l,r;
        //string s;
        char s[10];
        //while(cin>>n>>q)
        while(scanf("%lld%lld",&n,&q)!=EOF)//cin  cout会超时
        {
            ans=0;
            memset(sum,0,sizeof(sum));
            memset(lazy,0,sizeof(lazy));
            memset(mi,0,sizeof(mi));
            for(int i=1;i<=n;i++) scanf("%d",&b[i]);
                //cin>>b[i];
            Build(1,n,1);
            for(int i=1;i<=q;i++)
            {
                ans=0;
                scanf("%s%lld%lld",s,&l,&r);
                //cin>>s>>l>>r;
                if(s[0]=='a')
                {
                    Updata(1,n,1,l,r);
    
                }
                else
                {
                    Query(1,n,1,l,r);
                    printf("%lld
    ",ans);
                    //cout<<ans<<endl;
                }
            }
        }
        return 0;
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    PowerShell里的数组
    题解 cf gym 103261 D FFT Algorithm
    欧拉筛求积性函数的一般形式
    题解 LOJ 6053
    题解 SP34112 UDIVSUM
    题解 luogu P5162 WD与积木
    Java 关闭流同步输入输出
    题解 luogu P6620 [省选联考 2020 A 卷] 组合数问题
    hdu 6588 题解
    题解 cf gym 102979 E Expected Distance
  • 原文地址:https://www.cnblogs.com/caijiaming/p/10300967.html
Copyright © 2011-2022 走看看