一个本题不太寻常的解法。(需要正解的可以pass)
貌似题解区没有这么做的,但可能是我眼瞎。
\(\text{Part-I:核心思想}\)
对于每一个发射塔,左右都可能有发射的对象,即向左数第一个\(H\)的值大于自己本身\(H\)的值的塔,或向右数第一个\(H\)的值大于自己本身\(H\)的值的塔。
我们逐个考虑。设现在为第\(i\)个发射塔,要确定左边的发射的对象。
首先,没有的情况,即\(i=1\text{ 或 }\max\limits_{1\le k<i}H_k\le H_i\) 时。
若有,那么......
\[\texttt{Binary Search! 二分查找——}\]
有人就要问了:\(H\)不满足单调性,怎么二分?
\(H\)虽然不满足单调性,但是,我们先令\(L_x=\max\limits_{1\le y<x} H_y\),即\(H_1,H_2,...,H_{x-1}\)的最大值,\(L\)一定满足单调性!
对于\(L\)的维护,由于是静态的,所以ST表
是个不错的工具。
部分代码如下:
inline void find_left(int p)
{//此处的L存的是结果!!!
//query_max(x,y) 查询的是max{h[x],h[x+1],...,h[y]}。
if(p==1||query_max(1,p-1)<=h[p]) {L[p]=-1;return;}
int l=1,r=p;
while(r-l>1)
{
int mid=(l+r)>>1;
if(query_max(mid,p-1)>h[p]) l=mid;
else r=mid;
}
L[p]=l; return;
}
关于右边同理。
\(\text{Part-II:时间复杂度}\)
ST表
的建立:\(O(n\log_2 n)\)- 一次二分:\(O(\log_2 n)\)(
ST表
的查询一次为\(O(1)\))
\(\therefore \text{时间复杂度为}O(3n\log_2 n)\)
\(\text{Part-III:完整代码}\)
(需开O2)
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1e6 + 5;
int dp[maxn][25];
int h[maxn],v[maxn];
int n;
inline void init()
{
register int i,j;
for(i=1;i<=n;i++)
dp[i][0]=h[i];
for(j=1;j < 22;j++)
for(i=1;i+(1<<j)-1<=n;i++)
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
inline int query_max(int l,int r)
{
int temp=log2(r-l+1);
return max(dp[l][temp],dp[r-(1<<temp)+1][temp]);
}
inline int read(){int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return f*x;}
inline void write(int x){if(x<0){putchar('-');x=-x;}if(x>9)write(x/10);putchar(x%10+'0');return;}
int L[maxn],R[maxn];
long long ans[maxn];
inline void find_left(int p)
{
if(p==1||query_max(1,p-1)<=h[p]) {L[p]=-1;return;}
int l=1,r=p;
while(r-l>1)
{
int mid=(l+r)>>1;
if(query_max(mid,p-1)>h[p]) l=mid;
else r=mid;
}
L[p]=l; return;
}
inline void find_right(int p)
{
if(p==n||query_max(p+1,n)<=h[p]) {R[p]=-1;return;}
int l=p,r=n;
while(r-l>1)
{
int mid=(l+r)>>1;
if(query_max(p+1,mid)>h[p]) r=mid;
else l=mid;
}
R[p]=r; return;
}
signed main()
{
register int i;
scanf("%d",&n);
for(i=1;i<=n;i++) h[i]=read(),v[i]=read();
init();
for(i=1;i<=n;i++)
find_left(i),find_right(i);
for(i=1;i<=n;i++)
{
if(L[i]!=-1) ans[L[i]]+=v[i];
if(R[i]!=-1) ans[R[i]]+=v[i];
}
printf("%lld",*max_element(ans+1,ans+1+n));
return 0;
}
\(OVER.\)
原文地址:https://www.cnblogs.com/-Wallace-/p/12337863.html
时间: 2024-11-05 13:28:45