codevs 3304 水果姐逛水果街一

其实将整个链对折就得到一棵树。同样使用倍增表,考虑维护四个值:max,min,premax,submax,可以求解。

也可以用线段树:主体更新和倍增法相同,同样在每个区间内记录以上四个值。小技巧:在返回时直接返回一个struct。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 200005
using namespace std;
long long n,ma[maxn][30],mi[maxn][30],m,x,y,price[maxn],submax[maxn][30],premax[maxn][30];
long long anc[maxn][30];
long long ask(long long x,long long y)
{
long long minn=55667788,ans=0,maxnn=0;
if (x<y)
{
for (long long i=25;i>=0;i--)
{
if (x+(1<<i)<=y)
{
ans=max(submax[x][i],ans);
ans=max(ans,ma[x][i]-minn);
minn=min(minn,mi[x][i]);
x=anc[x][i];
}
}
}
else
{
swap(x,y);
for (long long i=25;i>=0;i--)
{
if (y-(1<<i)>=x)
{
ans=max(premax[x][i],ans);
ans=max(ans,maxnn-mi[x][i]);
maxnn=max(maxnn,ma[x][i]);
x=anc[x][i];
}
}
}
return ans;
}
int main()
{
scanf("%lld",&n);
for (long long i=1;i<=n;i++)
scanf("%lld",&price[i]);
for (long long i=1;i<=n;i++)
{
anc[i][0]=i+1;
ma[i][0]=max(price[i],price[i+1]);
mi[i][0]=min(price[i],price[i+1]);
submax[i][0]=price[i+1]-price[i];
premax[i][0]=price[i]-price[i+1];
}
for (long long e=1;e<=25;e++)
for (long long i=1;i<=n;i++)
{
ma[i][e]=max(ma[i][e-1],ma[anc[i][e-1]][e-1]);
mi[i][e]=min(mi[i][e-1],mi[anc[i][e-1]][e-1]);
submax[i][e]=max(max(submax[i][e-1],submax[anc[i][e-1]][e-1]),ma[anc[i][e-1]][e-1]-mi[i][e-1]);
premax[i][e]=max(max(premax[i][e-1],premax[anc[i][e-1]][e-1]),ma[i][e-1]-mi[anc[i][e-1]][e-1]);
anc[i][e]=anc[anc[i][e-1]][e-1];
}
scanf("%lld",&m);
for (long long i=1;i<=m;i++)
{
scanf("%lld%lld",&x,&y);
if (x==y) printf("0 ");
else printf("%lld ",ask(x,y));
}
return 0;
}

原文地址:https://www.cnblogs.com/ziliuziliu/p/5099032.html