POJ3250從多個方面考慮同一問題

來源:互聯網
上載者:User

有很多的方法過這題,以下介紹三種方法,主要思路是將序列反轉(其實不反轉也沒什麼),然後去找第i個元素左邊靠最右的比這個元素大的位置j,那麼i-j+1就是第i個元素對應的解。
第一種方法:利用線段樹動態更新,完成上部分的查詢,複雜度O(nlogn)。

對線段樹處理這類問題的方法就不詳細說明了,想要瞭解的,看這篇文章

 

My Code:

#include <cstdio><br />#include <cstring><br />#include <cstdlib><br />#include <algorithm><br />using namespace std;<br />const int MAX=80001;<br />const int oo=0x3f3f3f3f;<br />struct Node{<br />int l,r,val;<br />}seg[MAX<<2];<br />int h[MAX];<br />void init(int k,int l,int r){<br />seg[k].l=l;<br />seg[k].r=r;<br />seg[k].val=-1;<br />if(l==r){<br />return;<br />}<br />int mid=(l+r)>>1;<br />init(k<<1,l,mid);<br />init(k<<1|1,mid+1,r);<br />}<br />void add(int k,int idx){<br />if(seg[k].l==seg[k].r){<br />seg[k].val=idx;<br />return;<br />}<br />int mid=(seg[k].l+seg[k].r)>>1;<br />if(idx<=mid)add(k<<1,idx);<br />else add(k<<1|1,idx);<br />if(seg[k<<1|1].val!=-1&&h[seg[k<<1|1].val]>=h[seg[k<<1].val])seg[k].val=seg[k<<1|1].val;<br />else seg[k].val=seg[k<<1].val;<br />}<br />int read(int k,int idx,int v){<br />if(seg[k].l>idx)return -1;<br />if(h[seg[k].val]<v)return -1;<br />if(seg[k].l==seg[k].r)return seg[k].val;<br />int mid=(seg[k].l+seg[k].r)>>1;<br />if(idx>mid&&h[seg[k<<1|1].val]>=v){<br />return read(k<<1|1,idx,v);<br />}else{<br />return read(k<<1,idx,v);<br />}<br />}<br />int main(){<br />int n;<br />long long ret=0;<br />scanf("%d",&n);<br />h[0]=oo;<br />for(int i=1;i<=n;i++)scanf("%d",&h[i]);<br />reverse(h+1,h+n+1);<br />init(1,0,n);<br />add(1,0);<br />for(int i=1;i<=n;i++){<br />ret+=i-read(1,i-1,h[i])-1;<br />add(1,i);<br />}<br />printf("%lld/n",ret);<br />return 0;<br />}<br />

第二種方法:利用一個單調棧,棧內維護一個遞減的區間,記錄在此元素之前比其大的元素序列的下標。新的元素入隊,如果棧頂元素大於這個入隊元素,那麼結果就加上這個元素的下標減去棧頂元素下標再減去1,否則棧頂元素出棧,以此類推。演算法複雜度是O(n)的。

演算法實現其實很簡單,只要維護一個棧,用top表示棧頂下標就可以了。

 

My Code:

#include <cstdio><br />#include <cstring><br />#include <cstdlib><br />#include <algorithm><br />using namespace std;<br />const int MAX=80005;<br />const int oo=0x3f3f3f3f;<br />int st[MAX],h[MAX];<br />int main(){<br />int n;<br />scanf("%d",&n);<br />h[0]=oo;<br />for(int i=1;i<=n;i++)scanf("%d",&h[i]);<br />reverse(h+1,h+1+n);<br />int top=0;<br />long long ret=0;<br />st[top++]=0;<br />for(int i=1;i<=n;i++){<br />while(h[st[top-1]]<h[i])top--;<br />ret+=i-st[top-1]-1;<br />st[top++]=i;<br />}<br />printf("%lld/n",ret);<br />return 0;<br />}<br />

 

第三種方法:利用並查集的思路直接做。記錄r[i]表示第i個元素可以到達的最右邊的下標,那麼每次利用下面的方式壓縮路徑:
r[i]=i;
while(h[i]>h[r[i]+1])r[i]=r[r[i]+1];
細節處理看My Code,演算法複雜度是O(n*α(n))的。

 

My Code:

#include <cstdio><br />#include <cstring><br />#include <cstdlib><br />#include <algorithm><br />using namespace std;<br />const int MAX=80005;<br />const int oo=0x3f3f3f3f;<br />int r[MAX],h[MAX];<br />int main(){<br />int n;<br />long long ret=0;<br />scanf("%d",&n);<br />h[n]=oo;<br />for(int i=0;i<n;i++)scanf("%d",&h[i]);<br />r[n]=n;<br />for(int i=n-1;i>=0;i--){<br />r[i]=i;<br />while(h[i]>h[r[i]+1])r[i]=r[r[i]+1];<br />ret+=r[i]-i;<br />}<br />printf("%lld/n",ret);<br />return 0;<br />}<br />

 

三個演算法比較:

對於第一個演算法肯定是最慢的,畢竟O(nlogn)的時間複雜度加上線段樹的較大常數,和下面兩個O(n)或者近似O(n)的演算法來比,會遜色很多。

從後兩個演算法已耗用時間上看,O(n*α(n))的第三種演算法反而更快,可能是我單調棧常數太大了,或者我的序列反轉過的原因。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.