這道題本來是用dp做的,這幾天都在練dp,看了一下,可以用線段樹來做,就嘗試了一下,雖然不好寫,但是還是可以做的- -。
這題的關鍵在於預先處理出每個方格可以向左向右分別擴充多少長度,記錄l[i]和r[i]分別表示第i個格子可以向左向右擴充的格子數,那麼如果選中了第i個格子,面積就是(l[i]+r[i]+1)*h[i],這樣最後線性掃一遍就可以了。
l[i]的求法,最直接的方法就是枚舉,從該格子向左枚舉,找到第一個比它小的格子,這個格子右邊的都是可擴充的。
這樣做複雜度是O(n^2)的,對於100000的資料量來說是不可以接受的,所以我們需要最佳化,用線段樹維護每個區間的最小值,我們會發現這個格子事實上就是i號格子左邊區間的最靠右邊的比它小的格子,這樣就可以輕鬆轉化為給定區間求區間中最靠右的比x小的元素的id。
r[i]的求法類似,所以要維護兩棵線段樹。
最後問題迎刃而解,還要注意的就是需要用到long long類型。。。
My Code:
#include <cstdio><br />#include <cstring><br />#include <cstdlib><br />#include <algorithm><br />using namespace std;<br />const int MAX=100010;<br />struct Seg{<br />int l,r,id;<br />int mid(){<br />return (l+r)>>1;<br />}<br />}lt[MAX<<2],rt[MAX<<2];<br />int l[MAX],r[MAX];<br />long long h[MAX];<br />void initl(int k,int l,int r){<br />lt[k].l=l;<br />lt[k].r=r;<br />lt[k].id=-1;<br />if(l==r)return;<br />int mid=lt[k].mid();<br />initl(k<<1,l,mid);<br />initl(k<<1|1,mid+1,r);<br />}<br />void initr(int k,int l,int r){<br />rt[k].l=l;<br />rt[k].r=r;<br />rt[k].id=-1;<br />if(l==r)return;<br />int mid=rt[k].mid();<br />initr(k<<1,l,mid);<br />initr(k<<1|1,mid+1,r);<br />}<br />void setl(int k,int idx){<br />if(lt[k].l==lt[k].r){<br />lt[k].id=idx;<br />return;<br />}<br />int mid=lt[k].mid();<br />if(idx<=mid)setl(k<<1,idx);<br />else setl(k<<1|1,idx);<br />if(lt[k<<1|1].id!=-1&&h[lt[k<<1|1].id]<h[lt[k<<1].id]){<br />lt[k].id=lt[k<<1|1].id;<br />}else{<br />lt[k].id=lt[k<<1].id;<br />}<br />}<br />void setr(int k,int idx){<br />if(rt[k].l==rt[k].r){<br />rt[k].id=idx;<br />return;<br />}<br />int mid=rt[k].mid();<br />if(idx<=mid)setr(k<<1,idx);<br />else setr(k<<1|1,idx);<br />if(rt[k<<1].id!=-1&&h[rt[k<<1].id]<h[rt[k<<1|1].id]){<br />rt[k].id=rt[k<<1].id;<br />}else{<br />rt[k].id=rt[k<<1|1].id;<br />}<br />}<br />int readl(int k,int a,int b,long long x){<br />//if(lt[k].id!=-1)printf("Left %d %d %I64d/n",lt[k].l,lt[k].r,h[lt[k].id]);<br />if(h[lt[k].id]>x)return -1;<br />if(lt[k].l==lt[k].r)return lt[k].id;<br />int mid=lt[k].mid();<br />if(b<=mid)return readl(k<<1,a,b,x);<br />else if(a>mid)return readl(k<<1|1,a,b,x);<br />else{<br />if(lt[k<<1|1].id!=-1&&h[lt[k<<1|1].id]<=x){<br />return readl(k<<1|1,a,b,x);<br />}else{<br />return readl(k<<1,a,b,x);<br />}<br />}<br />}<br />int readr(int k,int a,int b,long long x){<br />if(h[lt[k].id]>x)return -1;<br />if(rt[k].l==rt[k].r)return rt[k].id;<br />int mid=rt[k].mid();<br />if(b<=mid)return readr(k<<1,a,b,x);<br />else if(a>mid)return readr(k<<1|1,a,b,x);<br />else{<br />if(rt[k<<1].id!=-1&&h[rt[k<<1].id]<=x){<br />return readr(k<<1,a,b,x);<br />}else{<br />return readr(k<<1|1,a,b,x);<br />}<br />}<br />}<br />int main(){<br />int n;<br />while(scanf("%d",&n),n){<br />for(int i=0;i<n;i++){<br />scanf("%I64d",&h[i]);<br />}<br />initl(1,0,n-1);<br />initr(1,0,n-1);<br />l[0]=0;<br />r[n-1]=0;<br />setl(1,0);<br />setr(1,n-1);<br />for(int i=1;i<n;i++){<br />int id=readl(1,0,i-1,h[i]);<br />setl(1,i);<br />if(id==-1){<br />l[i]=i;<br />}else{<br />l[i]=i-id-1;<br />if(h[i]==h[id])l[i]+=l[id]+1;<br />}<br />}<br />for(int i=n-2;i>=0;i--){<br />int id=readr(1,i+1,n-1,h[i]);<br />setr(1,i);<br />if(id==-1){<br />r[i]=n-1-i;<br />}else{<br />r[i]=id-i-1;<br />if(h[i]==h[id])r[i]+=r[id]+1;<br />}<br />}<br />//for(int i=0;i<n;i++)printf("%d ",l[i]);puts("");<br />//for(int i=0;i<n;i++)printf("%d ",r[i]);puts("");<br />long long ret=0;<br />for(int i=0;i<n;i++){<br />ret=max(ret,(l[i]+r[i]+1)*h[i]);<br />}<br />printf("%I64d/n",ret);<br />}<br />return 0;<br />}<br />