巴比伦花园
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 335 Solved: 39
Description
巴比伦花园在前6世纪由新巴比伦王国的尼布甲尼撒二世(Nebuchadnezzar)在巴比伦城为其患思乡病的王妃安美依迪丝(Amyitis)修建的。园中种植各种花草树木,远看犹如花园悬在半空中。当然这个伟大的奇迹现在已经不存在了,但幸运的是我们仍能从流传于后世的故事中窥看到它的蛛丝马迹。
据说花园被建造的时候,花园的座落处有一块巨大的石头,聪明的工匠决定把它打造成一个天然的阶梯,因为这块石头原本就凹凸不平的,形如:h1 , h2, h3 ……, hn。但是局限于当时的技术条件,工匠们只能把一段连续的区间:hi, hi+1, hi+2, ……, hj 加工成:
fi, fi+1, fi+2, ……, fj ,并且要满足三个条件:
1. fi+1 = fi + k,
2. fi>= 1,
3.fi <= hi.
Input
Output
请对每个询问都输出一行。
Sample Input
15 1 31 3 2 4 31 32 45 5
Sample Output
231
HINT
Source
解题思路:dp(i):表示从以h(i)为阶梯的起点,所能加工出的最长阶梯的最右端的位置,用线段树维护两个值(max{dp[i]-i+1}, max{dp[i]}),对于询问的区间pl, pr, 先在线段树上二分找到一个最左的dp[i]>=pr的位置l,然后在[pl, l-1]上询问一个最大的dp[i]-i+1
#include <stdio.h>
#include <string.h>
#include <stack>
#include <algorithm>
#include <iostream>
#include <set>
#include <map>
#include <math.h>
#include <queue>
using namespace std;
#define LL long long
const int M = 100000+10;
LL h[M];
int R[M],n,k,m;
struct node
{
int mari,mar;
} a[M<<2];
void build (int k,int l,int r)
{
if(l==r)
{
a[k].mari=R[l]-l+1;
a[k].mar=R[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
a[k].mari=max(a[k<<1].mari,a[k<<1|1].mari);
a[k].mar=max(a[k<<1].mar,a[k<<1|1].mar);
}
int f(int k,int l,int r,int ll,int rr)
{
if(a[k].mar<rr) return 0;
if(l==r) return l;
int mid=l+r>>1,res;
if(ll<=mid&&(res=f(k<<1,l,mid,ll,rr))) return res;
if(rr>mid&&(res=f(k<<1|1,mid+1,r,ll,rr))) return res;
}
int get(int k, int l, int r, int ll, int rr)
{
if (ll<=l&&r<=rr) return a[k].mari;
int mid=l+r>>1,res=0;
if (ll<=mid) res=max(res,get(k<<1,l,mid,ll,rr));
if (rr>mid) res=max(res,get(k<<1|1,mid+1,r,ll,rr));
return res;
}
int main ()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d %d", &n,&k,&m);
for (int i=1; i<=n; i++)
scanf("%lld",&h[i]);
LL hh=1;
int x=1;
for (int i=1; i<=n; i++,hh+=k)
{
while(h[i]<hh)
{
R[x++]=i-1;
hh-=k;
}
}
for(int i=x; i<=n; i++) R[i]=n;
build(1,1,n);
int l,r;
while(m--)
{
scanf("%d %d",&l,&r);
int x=f(1,1,n,l,r);
printf("%d\n",max(get(1,1,n,l,x-1),r-x+1));
}
}
return 0;
}