• Black Rock Shooter


    在人气动漫 Black Rock shooter 中,当加贺里对麻陶
    说出了“滚回去“以后,与此同时,在另一个心灵世界里,
    BRS 也遭到了敌人的攻击。此时,一共有 n 个攻击排成一行
    朝着她飞了过来,每个攻击有一个伤害值。并且每个攻击伤
    害可能随时变化。BRS 的攻击可以打掉一段连续的攻击。现
    在,给出 m 段攻击,求出 BRS 最多可以打掉此段里多少的
    伤害(就是说从给定一段里选择连续一段打掉)。伤害从 1
    到 n 编号。

    输入格式

    第一行 2 个整数:n , m
    第二行 n 个数:第 i 个数代表第 i 个攻击
    第 3 到 2+m 行:每行三个数 k,x,y。若 k=1,x,y
    代表查询的区间。若 k=2,代表第 x 个攻击伤害改为了 y
    所有的伤害值绝对值<=1000

    输出格式

    对于每次 k=1,输出一个整数代表最大值

    样例输入

    5 3
    1 2 -3 4 5
    1 2 3
    2 2 -1
    1 2 3

    样例输出

    2
    -1

    数据范围
    对于 20%的数据:n,m<=100
    对于 60%的数据:n,m<=3000
    对于 100%的数据:n<=500000,m<=100000

    【题解】
    这道题应该是一道有点裸的线段树,只是将模板的求和换作求最大值而已。即用线段树维护区间最大子段和。
    solution写法:区间合并线段树,维护lm,rm,mx.

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MAX=500005;
    struct tree
    {
        int sum;//本段总和
        int v;//本段中自身的最大子段
        int vl,vr;//本段连接左或右端点的最大子段
    }t[MAX<<2];
    int N,M,k,x,y;
    
    int gi()
    {
        int x=0,w=1;char ch=getchar();
        while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
        if (ch=='-') w=-1,ch=getchar();
        while (ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*w;
    }
    
    void Update(int now)
    {
        int lson=now<<1,rson=now<<1|1;
        t[now].v=max(t[lson].vr+t[rson].vl,max(t[lson].v,t[rson].v));
        t[now].vl=max(t[lson].vl,t[lson].sum+t[rson].vl);
        t[now].vr=max(t[rson].vr,t[rson].sum+t[lson].vr);
        t[now].sum=t[lson].sum+t[rson].sum;
    }
    
    void Build(int now,int l,int r)
    {
        if (l==r)
        {
            t[now].sum=t[now].v=t[now].vl=t[now].vr=gi();
            return;
        }
        int mid=(l+r)>>1;
        Build(now<<1,l,mid);
        Build(now<<1|1,mid+1,r);
        Update(now);
    }
    
    int Query_l(int now,int l,int r)//查询左连续的最大子段
    {
        if (l>=x&&r<=y)
             return t[now].vl;
        int mid=(l+r)>>1,res;
        res=Query_l(now<<1,l,mid);
        if (y>mid) res=max(res,t[now<<1].sum+Query_l(now<<1|1,mid+1,r));
        return res;
    }
    
    int Query_r(int now,int l,int r)//查询右连续的最大子段
    {
        if (l>=x&&r<=y)
            return t[now].vr;
        int mid=(l+r)>>1,res;
        res=Query_r(now<<1|1,mid+1,r);
        if (x<=mid) res=max(res,t[now<<1|1].sum+Query_r(now<<1,l,mid));
        return res;
    }
    
    //x y是询问区间
    int Query(int now,int l,int r)//区间最大子段
    {
        if (l>=x&&r<=y)
            return t[now].v;
        int mid=(l+r)>>1,res;
        if (y<=mid) res=Query(now<<1,l,mid);
        else if (x>mid) res=Query(now<<1|1,mid+1,r);
        else res=max(Query_r(now<<1,l,mid)+Query_l(now<<1|1,mid+1,r),max(Query(now<<1,l,mid),Query(now<<1|1,mid+1,r)));
        return res;
    }
    
    //把第x个数修改成y
    void Change(int now,int l,int r)
    {
        if (l==r)
        {
            t[now].sum=t[now].v=t[now].vl=t[now].vr=y;
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid) Change(now<<1,l,mid);
        else Change(now<<1|1,mid+1,r);
        Update(now);
    }
    
    int main()
    {
        freopen("BRS.in","r",stdin);
        freopen("BRS.out","w",stdout);
        N=gi();M=gi();
        Build(1,1,N);
        while (M--)
        {
            k=gi();x=gi();y=gi();
            if (k==1)
                printf("%d
    ",Query(1,1,N));
            else
                Change(1,1,N);
        }
        return 0;
    }
  • 相关阅读:
    汇编学习笔记(一)
    外部中断的资料
    喇叭的落幕
    红外模块
    SQL2005连接不上解决
    DataGrid中动态添加列,使用CheckBox选择行
    List和ObservableCollection的相互转化
    使用C#发送邮件
    C#委托与事件 简明
    Linq GroupBy 求和
  • 原文地址:https://www.cnblogs.com/yanshannan/p/7392299.html
Copyright © 2020-2023  润新知