题意:
给出一个序列,每个点都有货物其价格是周期变化的,只能从起点走向终点,每走一个点经过一天,不能再点上停留,给出起点终点问可获得的最大价值。
思路:
:
线段树维护 Max , Min 和 右子树的Max-左子树Min 的最大值(st)
但这样记录答案只是每个子树上的的答案,所以在查询时,还需要维护一下左右子树之间的答案
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ls (now<<1)
#define rs (now<<1|1)
#define lson l,mid,ls
#define rson mid+1,r,rs
#define int long long
#define Bug cout<<"here\n";
const int maxn=2e5+10;
struct node{
int Max,Min,l,r;
}e[20][maxn*4];
int b[10][maxn];
void up(node t[],int now){
t[now].l=t[rs].Max-t[ls].Min;
t[now].l=max(t[now].l,max(t[ls].l,t[rs].l));
t[now].r=t[ls].Max-t[rs].Min;
t[now].r=max(t[now].r,max(t[ls].r,t[rs].r));
t[now].Max=max(t[ls].Max,t[rs].Max);
t[now].Min=min(t[ls].Min,t[rs].Min);
}
void n_up(node &x,node a,node b)
{
x.l=b.Max-a.Min;
x.l=max(x.l,max(b.l,a.l));
x.r=a.Max-b.Min;
x.r=max(x.r,max(b.r,a.r));
x.Max=max(a.Max,b.Max);
x.Min=min(a.Min,b.Min);
}
void built(node t[], int st,int l,int r,int now)
{
int mid=(l+r)>>1;
if(l>r) return ;
t[now].l=t[now].r=0;
t[now].Max=t[now].Min=0;
while(l==r)
{
int k=(l+st)%7;
if(k==0) k=7;
if(st>=7)
{
k=8-k;
}
t[now].Max=t[now].Min=b[k][l];return ;
}
built(t,st,lson);
built(t,st,rson);
up(t,now);
}
node query(node t[],int l,int r,int L,int R,int now)
{
int mid=(l+r)>>1;
if(L<=l&&r<=R)
return t[now];
node ans,ans3=(node){0,0,0,0};
if(L<=mid) ans=query(t,l,mid,L,R,now<<1);
if(R>mid){
node ans2=query(t,mid+1,r,L,R,now<<1|1);
if(L<=mid) n_up(ans3,ans,ans2);
else ans3=ans2;
}
else ans3=ans;
return ans3;
}
#undef int
int main()
{
#define int long long
int n;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
int v,d;
scanf("%lld%lld",&v,&d);
for(int j=1;j<=4;j++)
b[j][i]=b[7-j+1][i]=v+(j-1)*d;
}
for(int i=1;i<=14;i++)
built(e[i],i-1,1,n,1);
int t;
scanf("%lld",&t);
while(t--)
{
int l,r;
scanf("%lld%lld",&l,&r);
if(l<r)
{
int k=(9-l%7)%7;
if(k==0) k=7;
int ans=query(e[k],1,n,l,r,1).l;
printf("%lld\n",max(ans,1ll*0));
}
else
{
int k=(l%7);
if(k==0)k=7;
k=15-k;
int ans=query(e[k],1,n,r,l,1).r;
printf("%lld\n",max(ans,1ll*0));
}
}
return 0;
}