POj 2823 單調佇列 / 優先佇列
阿新 • • 發佈:2018-12-24
解法1: 單調佇列
所謂單調佇列就是一個單調遞增或遞減的佇列,並不是什麼神奇的東西。
單調佇列(就遞增來說)嚴格來說就是隊頭的原素是最大的,不斷從隊尾加原素,如果隊尾的原素比要加入來的原素大,就不斷退隊,就到隊尾的原素比要加入來的原素小或等於要加入來的原素。
這題只要分別維護單調遞增和單調遞減的佇列,每讀入一個數就加入兩個佇列,然後從兩個隊頭拿兩個隊頂原素出來,[L,R](L,R分別Sliding Windows的左邊界和右邊界),如果拿出來的原素在左邊界的左邊就仍掉,取出來的原素在[L,R]內,就為結果。
程式碼G++超時了,C++ AC看來還要改進下!
#include <iostream> #include <cstdio> using namespace std; #define MAXN 1000000 struct cnode { int val; int INDEX; }maxqu[MAXN + 10];//遞增佇列(隊尾到隊頭遞增) cnode minqu[MAXN + 10];//遞減佇列 int minans; int maxans[MAXN + 10]; int mintop; int minrear; int maxtop; int maxrear; inline void mininsert(int n,int IND)//加入遞減佇列 { while(minqu[minrear].val> n&&minrear>=mintop)//隊尾原素比隊尾大,退隊 { minrear--; } minqu[++minrear].val = n;//加原素到隊尾 minqu[minrear].INDEX = IND; int i; /* cout<<"min"<<endl; for(i=mintop;i<=minrear;i++) { cout<<minqu[i].val<<" "; } cout<<endl; cout<<"min"<<endl;*/ } inline void maxinsert(int n,int IND)//加入遞增佇列 { while(maxqu[maxrear].val < n&&maxrear>=maxtop)//隊尾原素比隊尾小,退隊 { maxrear--; } maxqu[++maxrear].val = n;//加原素到隊尾 maxqu[maxrear].INDEX = IND; /*cout<<"max"<<endl; int i; for(i=maxtop;i<=maxrear;i++) { cout<<maxqu[i].val<<" "; } cout<<endl; cout<<"max"<<endl;*/ } inline int fmintop(int i,int k)//取隊頭原素 { //return minqu[mintop].val; while(minqu[mintop].INDEX < i&&mintop<=minrear)//隊頭原素在[L,R]的左邊,仍掉 { mintop++; } return minqu[mintop].val; } inline int fmaxtop(int i,int k)//取隊頭原素 { //maxqu[maxtop].val; while(maxqu[maxtop].INDEX < i&&maxtop<=maxrear)////隊頭原素在[L,R]的左邊,仍掉 { maxtop++; } return maxqu[maxtop].val; } int main() { int n,m; int i; int num; while(scanf("%d %d",&n,&m) != EOF) { mintop = 0; minrear = -1; maxtop = 0; maxrear = -1; for(i = 0;i < n;i++) { scanf("%d",&num); mininsert(num,i); maxinsert(num,i); if(i>=m-1) { minans=fmintop(i-m+1,i); maxans[i-m+1]=fmaxtop(i-m+1,i); printf("%d",minans); if(i!=n-1) { printf(" "); } } } n = n-m+1; printf("\n"); for(i=0;i<n;i++) { printf("%d",maxans[i]); if(i!=n-1) { printf(" "); } } printf("\n"); } return 0; }
解法2: 優先佇列
用上面的做法,換一種資料結構-堆,同樣可以解決這道題,也是不斷放入最小堆,最大堆,不在[L,R]區間的仍掉
程式碼G++超時了,C++ AC看來還要改進下!
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; #define MAXN 1000000 struct cnode { int val; int INDEX; /* bool operator < (cnode e)//從大到小 { return e.val<val; }*/ }node; struct cmp1{ bool operator()(const cnode e1,const cnode e2) { return e1.val<e2.val; } }; struct cmp2 { bool operator()(const cnode e1,const cnode e2) { return e1.val<e2.val? false:true; } }; int maxans[MAXN + 10]; int main() { int n,m; int i; int num; while(scanf("%d %d",&n,&m) != EOF) { priority_queue<cnode,vector<cnode>,cmp1> maxqu;//最大堆 priority_queue<cnode,vector<cnode>,cmp2> minqu;//最小堆 for(i = 0;i < n;i++) { scanf("%d",&node.val); node.INDEX = i; minqu.push(node); maxqu.push(node); if(i>=m-1) { node = minqu.top(); while(node.INDEX<i-m+1)//不在[L,R]區間的仍掉 { minqu.pop(); node = minqu.top(); } printf("%d%c",node.val,i==n-1 ? '\n':' '); node = maxqu.top(); while(node.INDEX<i-m+1)//不在[L,R]區間的仍掉 { maxqu.pop(); node = maxqu.top(); } maxans[i-m+1] = node.val; } } n = n - m + 1; for(i = 0;i < n;i++) { printf("%d%c",maxans[i],i==n-1 ? '\n':' '); } } return 0; }