[LuoguP1901]发射站

一个本题不太寻常的解法。(需要正解的可以pass)

貌似题解区没有这么做的,但可能是我眼瞎

\(\text{Part-I:核心思想}\)

对于每一个发射塔,左右都可能有发射的对象,即向左数第一个\(H\)的值大于自己本身\(H\)的值的塔,或向右数第一个\(H\)的值大于自己本身\(H\)的值的塔。

我们逐个考虑。设现在为第\(i\)个发射塔,要确定左边的发射的对象。

首先,没有的情况,即\(i=1\text{ 或 }\max\limits_{1\le k 时。

若有,那么......

\[\texttt{Binary Search! 二分查找——}\]

有人就要问了:\(H\)不满足单调性,怎么二分?

\(H\)虽然不满足单调性,但是,我们先令\(L_x=\max\limits_{1\le 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
#include
#include
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<'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.\)

你可能感兴趣的:([LuoguP1901]发射站)