看到这题我就想到了2018预赛的毒瘤双向链表。。。
然而现在我还是不会。
于是我用表水过了这题。
对于发射站,以找它左边第一个比它大的发射站为例:
我们可以通过二分来找到最大的,满足
。
表示区间
中的最大高度。
对于区间高度最小值,我们可以用线段树或者表来维护。
如果用线段树,预处理是,查询是
,无法满足要求。
而表的查询是
的,就可以将总查询复杂度减小到
。
于是复杂度就是。
#include<iostream> #include<cstring> #include<cstdio> void read(int &s); #define ll long long int #define rep(i,a,b) for(int i=(a);i<=(b);i++) using namespace std; const int maxn=1000100; int maxx(int a,int b){return a<b?b:a;} int jie[maxn]; int n,h[maxn],v[maxn]; int st[maxn][23],lg2[maxn],mi2[23]; void csh(){ memset(jie,0,sizeof(jie)); lg2[1]=0; rep(i,2,n) lg2[i]=lg2[i/2]+1; mi2[0]=1; rep(k,1,lg2[n]+1)mi2[k]=mi2[k-1]+mi2[k-1]; rep(i,1,n)st[i][0]=h[i]; rep(k,1,lg2[n]) for(int i=1;i+mi2[k]-1<=n;i++) st[i][k]=maxx(st[i][k-1],st[i+mi2[k-1]][k-1]); } int q(int l,int r){ int k=lg2[r-l+1]; return maxx(st[l][k],st[r-mi2[k]+1][k]); } int Ans=0; void worrk(){ rep(i,1,n){ if(i!=1&&q(1,i-1)>h[i]){ int l=1,r=i-1,mid; while(l<r){ mid=(l+r+1)>>1; if(q(mid,i-1)>h[i])l=mid; else r=mid-1; } jie[l]+=v[i]; } if(i!=n&&q(i+1,n)>h[i]){ int l=i+1,r=n,mid; while(l<r){ mid=(l+r)>>1; if(q(i+1,mid)>h[i])r=mid; else l=mid+1; } jie[l]+=v[i]; } } rep(i,1,n)Ans=maxx(Ans,jie[i]); cout<<Ans; } int main(){ read(n); rep(i,1,n)read(h[i]),read(v[i]); csh(); worrk(); return 0; } void read(int &s){ s=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();} }