codeforces 516c// Drazil and Park// Codeforces Round #292(Div. 1)

题意:一个圆环上有树,猴子上下其中一棵树,再沿着换跑,再上下另一棵树。给出一个区间,问最大的运动距离是。

给出区间大小dst,和数高数组arr。

设区间[x,y],a[x]=2*arr[x]+dst[1]+dst[2]+......dst[x]。b[x]=2*arr[x]-dst[1]-dst[2]-......dst[x]。[x,y]在线段树中就是a[y]+b[x]。线段树分为很多区间,用数组a,b,s,记录当前区间的a,b最大值,s记录该区间里所有的情况中的爬树+路程的最大值,就是两个子区间中a最大的和b最大的。叶子节点用上面的公式计算。叶子节点s为0,其它的要么区间的最大值来自子区间的s值,要么是左区间的a值+右区间的b值,或者左的b值+右的a,以上几个的最大值。查询的时候查s值。查询结果要返回a,b,s。比如查[1,3]分为[1,2]和[3],那么结果是[1,2]的s,[3]的s,[1,2]的a+[3]的b,[1,2]的b+[3]的a,以上的最大值。因此a,b,c都要返回。

乱码:

#pragma comment(linker,"/STACK:1024000000,1024000000") 
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
#include <stack>
using namespace std;
const int SZ=8e5+10,INF=0x7FFFFFFF;
typedef long long lon;
lon mod=1000000009;
lon srcdst[SZ],dst[SZ],tall[SZ],a[SZ],b[SZ],s[SZ],arr[SZ];
lon n,m;

void init(lon n)
{
    for(lon i=2;i<=n+1;++i)
    {
        cin>>dst[i];
    }
    for(lon i=n+2;i<2*n+1;++i)
    {
        dst[i]=dst[i-n];
    }
    for(lon i=2;i<=2*n+1;++i)
    {
        dst[i]+=dst[i-1];
    }
    for(lon i=1;i<=n;++i)cin>>arr[i];
}

void pushup(lon rt)
{
    a[rt]=max(a[rt*2],a[rt*2+1]);
    b[rt]=max(b[rt*2],b[rt*2+1]);
    lon m1=max(s[rt*2],s[rt*2+1]);
    lon m2=max(a[rt*2]+b[rt*2+1],a[rt*2+1]+b[rt*2]);
    s[rt]=max(m1,m2);
}

void build(lon ll,lon rr,lon rt)
{
    if(ll==rr)
    {
        lon real=(ll-1)%(n/2)+1;
        a[rt]=2*arr[real]+dst[ll];
        b[rt]=2*arr[real]-dst[ll];
        //cout<<ll<<" "<<a[rt]<<" "<<b[rt]<<endl;
        return;
    }
    if(ll>rr)return;
    lon mid=(ll+rr)/2;
    build(ll,mid,rt*2);
    build(mid+1,rr,rt*2+1);
    pushup(rt);
}

struct nd{
    lon a,b,s;
    nd (lon _a=0,lon _b=0,lon _s=0):a(_a),b(_b),s(_s){}
    bool operator==(const nd &rbs)const
    {
        return a==rbs.a&&b==rbs.b&&s==rbs.s;
    }
};

nd qry(lon ll,lon rr,lon ql,lon qr,lon rt)
{
    nd res1,res2,rbs;
    if(ll>=ql&&rr<=qr)
    {
        nd tmp;
        tmp.a=a[rt],tmp.b=b[rt],tmp.s=s[rt];
        return tmp;
    }
    //cout<<ll<<" "<<rr<<" "<<ql<<" "<<qr<<endl;
    if(rr<ql||ll>qr)return rbs;
    lon mid=(ll+rr)/2;
    if(rr>=ql)res1=qry(ll,mid,ql,qr,rt*2);
    if(ll<=qr)res2=qry(mid+1,rr,ql,qr,rt*2+1);
    if(res1==rbs)return res2;
    else if(res2==rbs)return res1;
    else
    {
        lon max1=max(res1.s,res2.s);
        lon max2=max(res1.a+res2.b,res1.b+res2.a);
        res1.s=max(max1,max2);
        res1.a=max(res1.a,res2.a);
        res1.b=max(res1.b,res2.b);
        return res1;
    }
}

int main()
{
    std::ios::sync_with_stdio(0);
    //freopen("d:\\1.txt","r",stdin);
    cin>>n>>m;
    init(n);
    n=2*n+1;
    build(1,n,1);
    for(lon i=0;i<m;++i)
    {
        lon ql,qr;
        cin>>ql>>qr;
        if(ql<=qr)
        {
            swap(ql,qr);
            ++ql;
            qr+=n/2-1;
        }
        else
        {
            swap(ql,qr);
            ++ql,--qr;
        }
        cout<<qry(1,n,ql,qr,1).s<<endl;
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/gaudar/p/9683478.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值