zoukankan      html  css  js  c++  java
  • codeforces#1136E. Nastya Hasn't Written a Legend(二分+线段树)

    题目链接:

    http://codeforces.com/contest/1136/problem/E

    题意:

    初始有a数组和k数组

    有两种操作,一,求l到r的区间和,二,$a_ipm x$

    并且会有一个连锁反应

    $$whileleft ( a_{i+1}<a_i+k_i ight )a_{i+1}=a_i+k_i,i++ $$

    数据范围:

    $2 leq n leq 10^{5}$
    $-10^{9} leq a_i leq 10^{9}$
    $-10^{6} leq k_i leq 10^{6}$
    $1 leq q leq 10^{5}$
    $1 leq i leq n$,$0 leq x leq 10^{6}$
    $1 leq l leq r leq n$



    分析: 

     对于每次修改,我们可以用二分查找到连锁的末尾。

    而对于一个被修改后的区间$(i,r)$的元素$a_x$,它由两部分组成$a_x=a_i+sum_{j=i}^{x-1}k_j$

    两部分的值都可以轻易算出,然后用两颗线段树分别记录两部分的区间和(一颗线段树也行)。

    用到前缀和的前缀和,还有懒惰标记

    具体实现见ac代码

     ac代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=1e5+10;
    const ll INF=1e18;
    ll sum1[maxn],sum2[maxn],treea[4*maxn],treeb[4*maxn],lazya[4*maxn],lazyb[4*maxn];
    int a[maxn];
    void bulida(int l,int r,int rt)
    {
        int md=(r+l)/2;
        if(r==l)
        {
            treea[rt]=a[l];
            return;
        }
        bulida(l,md,rt*2);
        bulida(md+1,r,rt*2+1);
        treea[rt]=treea[rt*2]+treea[rt*2+1];
    }
    void pushdowna(int l,int r,int rt)
    {
        int md=(l+r)/2;
        if(lazya[rt]!=-INF)
        {
            treea[rt*2]=(md-l+1)*lazya[rt];
            treea[rt*2+1]=(r-md-1+1)*lazya[rt];
            lazya[rt*2]=lazya[rt*2+1]=lazya[rt];
            lazya[rt]=-INF;
        }
    }
    ll quera(int l,int r,int nowl,int nowr,int rt)
    {
        if(r<nowl||l>nowr)return 0;
        int md=(nowr+nowl)/2;
        if(l<=nowl&&r>=nowr)return treea[rt];
        pushdowna(nowl,nowr,rt);
        return quera(l,r,nowl,md,rt*2)+quera(l,r,md+1,nowr,rt*2+1);
    }
    void updataa(ll x,int l,int r,int nowl,int nowr,int rt)
    {
        if(r<nowl||l>nowr)return ;
        int md=(nowr+nowl)/2;
        if(l<=nowl&&r>=nowr)
        {
            treea[rt]=(nowr-nowl+1)*x;
            lazya[rt]=x;
            return ;
        }
        pushdowna(nowl,nowr,rt);
        updataa(x,l,r,nowl,md,rt*2);
        updataa(x,l,r,md+1,nowr,rt*2+1);
        treea[rt]=treea[rt*2]+treea[rt*2+1];
    }
    
    void pushdownb(int l,int r,int rt)
    {
        int md=(l+r)/2;
        if(lazyb[rt]!=-INF)
        {
            treeb[rt*2]=sum2[md-1]-sum2[l-2]+(l-md-1)*sum1[lazyb[rt]-1];
            treeb[rt*2+1]=sum2[r-1]-sum2[md+1-2]+(md+1-r-1)*sum1[lazyb[rt]-1];
            lazyb[rt*2]=lazyb[rt*2+1]=lazyb[rt];
            lazyb[rt]=-INF;
        }
    }
    void updatabb(ll x,int pos,int nowl,int nowr,int rt)
    {
        int md=(nowr+nowl)/2;
        if(nowl==nowr)
        {
            treeb[rt]=x;
            return ;
        }
        pushdownb(nowl,nowr,rt);
        if(pos>=md+1)updatabb(x,pos,md+1,nowr,rt*2+1);
        else updatabb(x,pos,nowl,md,rt*2);
        treeb[rt]=treeb[rt*2]+treeb[rt*2+1];
    }
    ll querb(int l,int r,int nowl,int nowr,int rt)
    {
        if(r<nowl||l>nowr)return 0;
        int md=(nowr+nowl)/2;
        if(l<=nowl&&r>=nowr)return treeb[rt];
        pushdownb(nowl,nowr,rt);
        return querb(l,r,nowl,md,rt*2)+querb(l,r,md+1,nowr,rt*2+1);
    }
    void updatab(ll x,int l,int r,int nowl,int nowr,int rt)
    {
        if(r<nowl||l>nowr)return ;
        int md=(nowr+nowl)/2;
        if(l<=nowl&&r>=nowr)
        {
            treeb[rt]=sum2[nowr-1]-sum2[nowl-2]+(nowl-nowr-1)*sum1[x-1];
            lazyb[rt]=x;
            return ;
        }
        pushdownb(nowl,nowr,rt);
        updatab(x,l,r,nowl,md,rt*2);
        updatab(x,l,r,md+1,nowr,rt*2+1);
        treeb[rt]=treeb[rt*2]+treeb[rt*2+1];
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        for(int i=1; i<=n-1; i++)
        {
            int x;
            scanf("%d",&x);
            sum1[i]=sum1[i-1]+x;
            sum2[i]=sum2[i-1]+sum1[i];
        }
        for(int i=0; i<4*maxn; i++)lazya[i]=lazyb[i]=-INF;
        bulida(1,n,1);
        int T;
        scanf("%d",&T);
        while(T--)
        {
            getchar();
            char key;
            scanf("%c",&key);
            if(key=='s')
            {
                int l,r;
                scanf("%d %d",&l,&r);
                printf("%lld
    ",quera(l,r,1,n,1)+querb(l,r,1,n,1));
            }
            else if(key=='+')
            {
                ll x,add;
                scanf("%lld %lld",&x,&add);
                add=quera(x,x,1,n,1)+querb(x,x,1,n,1)+add;
                int st=x,en=n;
                while(st!=en)
                {
                    int md=(st+en)/2;
                    if(sum1[md+1-1]-sum1[x-1]+add>=querb(md+1,md+1,1,n,1)+quera(md+1,md+1,1,n,1))st=md+1;
                    else en=md;
                }
                updataa(add,x,st,1,n,1);
                updatab(x,x+1,st,1,n,1);
                updatabb(0,x,1,n,1);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    创建应用程序菜单与菜单融合 
    FastReport 内置函数的用法与注意
    Visual Basic 2005 中的程式語言加強功能
    写作关键用词及短语汇总
    序列化FastReport
    Only Time(惟有时光)
    bcd
    【分享】微软产品全部序列号,盖茨会哭的~~~
    TADOQuery parameter对象被不正确地定义。提供了不一致或不完整的信息
    两相四线步进电机驱动代码
  • 原文地址:https://www.cnblogs.com/carcar/p/10758424.html
Copyright © 2011-2022 走看看