Codeforces Round #292 (Div. 2)E. Drazil and Park——线段树

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

具体解释看这个http://blog.csdn.net/u013654696/article/details/43898869

每个节点维护3个域
A[rt]=2*h[l]+d[l-1]
B[rt]=2*h[l]-d[l-1]
s[rt]=max energy
其中d[l]表示1到l的距离
将环变为线性的1,2…n,1,2…n的2n长度的区间

当一个父亲节点的左右孩子都要查询的时候,s[rt]=max(B[rt<<1]+A[rt<<1|1],max(s[rt<<1],s[rt<<1|1])
否则s[rt]=所查询到的某一边的孩子的s,然后再记录该孩子的A,B值
注意的是u!=v

对于查询,举个例子,要查询区间[3,6]

查询到结点9,没有查询到结点8,所以当前max energy=s[9]=0,记录当前max A=A[9],max B=B[9]
查询到结点5,也查询到结点5,所有当前max energy=max(左孩子的最大,右孩子的最大,跨区间的最大)

语言表达能力好差。。。

217 ms 21900 KB

#include<bits/stdc++.h>
#define ll long long
#define inf (~0ull>>1)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=2e5+10;
using namespace std;
ll a[maxn<<2],b[maxn<<2],s[maxn<<2];
ll d[maxn],h[maxn];
int n,m;
struct node{
    ll a,b,mx;
    node(ll a,ll b,ll mx):a(a),b(b),mx(mx){}
};
node null=node(-inf,-inf,0);
void push_up(int rt){
    a[rt]=max(a[rt<<1],a[rt<<1|1]);
    b[rt]=max(b[rt<<1],b[rt<<1|1]);
    s[rt]=max(a[rt<<1]+b[rt<<1|1],max(s[rt<<1],s[rt<<1|1]));
}
void build(int l,int r,int rt){
    if(l==r){
        a[rt]=2*h[l]-d[l-1];
        b[rt]=2*h[l]+d[l-1];
        s[rt]=0;
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}
void _merge(node x,node y,node& z){
    z.mx=max(x.mx,y.mx);
    z.a=max(x.a,y.a);
    z.b=max(x.b,y.b);
    z.mx=max(z.mx,x.a+y.b);
}
node query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R){
        node x=node(a[rt],b[rt],s[rt]);
        return x;
    }
    int m=(l+r)>>1;
    node lx=null,ry=null,res=null;
    if(L<=m) lx=query(L,R,lson);//左孩子的信息
    if(m<R) ry=query(L,R,rson);//右孩子的信息
    if(lx.a==-inf) //左孩子没有查询
 {res.a=max(res.a,ry.a);res.b=max(res.b,ry.b);res.mx=max(res.mx,ry.mx);}
    else if(ry.a==-inf) //右孩子没有查询
 {res.a=max(res.a,lx.a);res.b=max(res.b,lx.b);res.mx=max(res.mx,lx.mx);}
    else _merge(lx,ry,res);//都查询了
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%I64d",&d[i]);
    for(int i=1;i<=n;++i) scanf("%I64d",&h[i]);
    for(int i=1;i<=n;++i){
        d[i+n]=d[i];
        h[i+n]=h[i];
    }
    for(int i=1;i<=(n<<1);++i) d[i]=d[i-1]+d[i];
    build(1,n<<1,1);
    int x,y;
    ll A,B;
    while(m--){
        scanf("%d%d",&x,&y);
        if(x<=y)
            printf("%I64d\n",query(y+1,x+n-1,1,n<<1,1).mx);
        else
            printf("%I64d\n",query(y+1,x-1,1,n<<1,1).mx);
    }
    return 0;
}

你可能感兴趣的:(Codeforces Round #292 (Div. 2)E. Drazil and Park——线段树)