单调队列学习小记 Poj 2823 + Hdu 3530 (deque)
2013-06-17 14:09
316 查看
以前学过的东西,拿出来复习下。
poj2823 单调队列(含单调队列的学习) - Jason Damon博客园
http://www.cnblogs.com/Jason-Damon/archive/2012/04/19/2457889.html
单调队列 - Hackbuteer1的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/hackbuteer1/article/details/7424466
Poj 2823 Sliding Window
题目链接:http://poj.org/problem?id=2823
思路:单调队列的模板题,用线段树也可以做,但效率低些。
下面给出四份代码。
第一份是复习过程中参照上面的博客写的,比较直接也比较繁琐。
第二份是回忆起这东西究竟怎么用之后写的。
第三份是用线段树实现的。
第四份于2013-8-21更新,用了STL的deque容器,代码参考自:http://blog.csdn.net/wiking__acm/article/details/9970407#comments
deque比线段树还慢……9000ms
Hdu 3530 Subsequence
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3530
题意:给出一个序列,求最长的连续子序列,使得 M<=Max-Min<=K
思路:维护两个单调队列,分别存储范围内的最大值和最小值,当队首元素之差大于k时,看哪个的队首元素比较靠前,就把谁往后移动 。
poj2823 单调队列(含单调队列的学习) - Jason Damon博客园
http://www.cnblogs.com/Jason-Damon/archive/2012/04/19/2457889.html
单调队列 - Hackbuteer1的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/hackbuteer1/article/details/7424466
Poj 2823 Sliding Window
题目链接:http://poj.org/problem?id=2823
思路:单调队列的模板题,用线段树也可以做,但效率低些。
下面给出四份代码。
第一份是复习过程中参照上面的博客写的,比较直接也比较繁琐。
第二份是回忆起这东西究竟怎么用之后写的。
第三份是用线段树实现的。
第四份于2013-8-21更新,用了STL的deque容器,代码参考自:http://blog.csdn.net/wiking__acm/article/details/9970407#comments
deque比线段树还慢……9000ms
//单调队列 #include <cstdio> #include <iostream> using namespace std; const int N=1000005; int data ; //存储数据 int Q ; //队列 int P ; //存储A[i]中的下标i int Min ; //输出最小 int Max ; //输出最大 int n,k; void Get_min () { int i; int head=1,tail=0; for (i=0;i<k-1;i++) //将前k个元素入队 { while (head<=tail && Q[tail]>=data[i]) //队尾元素大于要插入的数 tail--; Q[++tail]=data[i]; P[tail]=i; } for (;i<n;i++) { while (head<=tail && Q[tail]>=data[i]) --tail; Q[++tail]=data[i]; P[tail]=i; while (P[head]<i-k+1) //判断数是否过时,即窗口是否已经划过这个数,从0开始计数 head++; Min[i-k+1]=Q[head]; } } void Get_max () { int i; int head=1,tail=0; for (i=0; i<k-1; i++) { while (head<=tail && Q[tail]<=data[i]) //队尾元素小于要插入的值 --tail; Q[++tail]=data[i]; P[tail]=i; } for (;i<n;i++) { while (head<=tail && Q[tail]<=data[i]) //队尾元素小于要插入的值 --tail; Q[++tail]=data[i]; P[tail]=i; while (P[head]<i-k+1) //判断数是否过时,即窗口是否已经划过这个数,从0开始计数 head++; Max[i-k+1]=Q[head]; } } int main () { #ifdef ONLINE_JUDGE #else freopen("read.txt","r",stdin); #endif int i; scanf("%d%d",&n,&k); for (i=0; i<n; i++) scanf("%d",&data[i]); Get_min (); Get_max (); for (i=0;i<n-k+1;i++) printf(i==n-k?"%d\n":"%d ",Min[i]); for (i=0;i<n-k+1;i++) printf(i==n-k?"%d\n":"%d ",Max[i]); return 0; }
#include <cstdio> const int N=1000005; int data ,Q ; int n,k,head,tail; void Deal_Min () { head=tail=0; Q[0]=0; for (int i=1;i<=n;i++) { while (head<tail && data[i] <= data[Q[tail-1]]) tail--; Q[tail]=i; //队列中存储元素下标 tail++; if (i>=k) { while (head<tail && Q[head]<=i-k) //过期 head++; printf("%d ",data[Q[head]]); //队首元素一定是当前所求元素 } } printf("\n"); } void Deal_Max () { head=tail=0; Q[0]=0; for (int i=1;i<=n;i++) { while (head<tail && data[i] >= data[Q[tail-1]]) tail--; Q[tail]=i; tail++; if (i>=k) { while (head<tail && Q[head]<=i-k) head++; printf("%d ",data[Q[head]]); } } printf("\n"); } int main () { scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) scanf("%d",&data[i]); Deal_Min(); Deal_Max(); return 0; }
#include <cstdio> #define min(x,y) ((x)<(y)?(x):(y)) #define max(x,y) ((x)>(y)?(x):(y)) const int INF=0x7fffffff; const int N=1000010; int n,k,MAX,MIN; struct Node { int nmax,nmin,left,right; }a[3*N]; int datamax ,datamin ; void Build (int t,int left,int right) { a[t].left=left; a[t].right=right; a[t].nmin=INF; //注意赋值正负 a[t].nmax=-INF; if (left==right) return; int mid=(left+right)>>1; Build(t*2,left,mid); Build(t*2+1,mid+1,right); } void Insert (int t,int target,int val) { if (a[t].left==target && a[t].right==target) { a[t].nmax=a[t].nmin=val; return; } a[t].nmax=max(a[t].nmax,val); a[t].nmin=min(a[t].nmin,val); int mid=(a[t].left+a[t].right)>>1; if (target<=mid) Insert(t*2,target,val); else Insert(t*2+1,target,val); } void Query (int t,int left,int right) { if (a[t].nmin>=MIN && a[t].nmax<=MAX) return; if (a[t].left==left && a[t].right==right) { MIN=min(MIN,a[t].nmin); MAX=max(MAX,a[t].nmax); return; } int mid=(a[t].left+a[t].right)>>1; if (right<=mid) Query(t*2,left,right); else if (left>mid) Query(t*2+1,left,right); else { Query(t*2,left,mid); Query(t*2+1,mid+1,right); } } int main () { int i,temp; scanf ("%d%d",&n,&k); Build(1,1,n); for (i=1;i<=n;i++) { scanf("%d",&temp); Insert(1,i,temp); } for (i=1;i<=n-k+1;i++) { MAX=-INF; MIN=INF; Query(1,i,i+k-1); datamax[i]=MAX; datamin[i]=MIN; } for (i=1;i<=n-k+1;i++) printf(i==n-k+1?"%d\n":"%d ",datamin[i]); for (i=1;i<=n-k+1;i++) printf(i==n-k+1?"%d\n":"%d ",datamax[i]); return 0; }
#include <cstdio> #include <queue> using namespace std; const int N = 1000005; typedef pair<int,int> P; deque<P> Q1; deque<P> Q2; int ans1 ,ans2 ; int main () { int n,k,x,i; while (~scanf("%d%d",&n,&k)) { while (!Q1.empty()) Q1.pop_back(); while (!Q2.empty()) Q2.pop_back(); for (i=0;i<n;i++) { scanf("%d",&x); while (!Q1.empty() && Q1.back().first >= x) Q1.pop_back(); Q1.push_back(P(x,i)); while (!Q1.empty() && Q1.front().second <= i-k) Q1.pop_front(); ans1[i] = Q1.front().first; while (!Q2.empty() && Q2.back().first <= x) Q2.pop_back(); Q2.push_back(P(x,i)); while (!Q2.empty() && Q2.front().second <= i-k) Q2.pop_front(); ans2[i] = Q2.front().first; } for (i=k-1;i<n;i++) printf(i==n-1?"%d\n":"%d ",ans1[i]); for (i=k-1;i<n;i++) printf(i==n-1?"%d\n":"%d ",ans2[i]); } return 0; }
Hdu 3530 Subsequence
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3530
题意:给出一个序列,求最长的连续子序列,使得 M<=Max-Min<=K
思路:维护两个单调队列,分别存储范围内的最大值和最小值,当队首元素之差大于k时,看哪个的队首元素比较靠前,就把谁往后移动 。
#include <cstdio> #include <cstring> #define max(x,y) ((x)>(y)?(x):(y)) const int N=100005; int data ,Qmin ,Qmax ; int n,m,k,hmin,tmin,hmax,tmax; int main () { while (~scanf("%d%d%d",&n,&m,&k)) { int i,s=0,ans=0; //ans初始化为-1 WA for (i=0;i<n;i++) scanf("%d",&data[i]); hmin=hmax=0; tmin=tmax=-1; memset(Qmin,-1,sizeof(Qmin)); memset(Qmax,-1,sizeof(Qmax)); for (i=0;i<n;i++) { while (hmin<=tmin && data[i] <= data[Qmin[tmin]]) tmin--; Qmin[++tmin]=i; //队列中存储元素下标 while (hmax<=tmax && data[i] >= data[Qmax[tmax]]) tmax--; Qmax[++tmax]=i; //当队首元素对应值之差超过上限,下标小的往后移 while (data[Qmax[hmax]] - data[Qmin[hmin]] > k) if (Qmin[hmin] < Qmax[hmax]) s=Qmin[hmin++]+1; else s=Qmax[hmax++]+1; if (data[Qmax[hmax]] - data[Qmin[hmin]] >= m) ans=max(ans,i-s+1); } printf("%d\n",ans); } return 0; }
相关文章推荐
- poj 2823 单调队列 deque写法
- 单调队列入门——POJ - 2823,HDU - 3530,HDU - 2430
- poj 2823 单调队列入门题(内含手写队列的学习和模板)
- Poj 2823 Sliding Window【单调队列学习】模板记录
- POJ 2823 Sliding Window - dp&单调队列优化
- POJ 2823 Sliding Window 单调队列+输入输出外挂
- POJ 2823(单调队列)
- Sliding Window POJ - 2823 单调队列
- Poj 2823 Sliding Window(单调队列)
- POJ 2823 Sliding Window(单调队列入门水题)
- poj 2823 Sliding Window 单调队列或线段树
- POJ 2823 Sliding Window 单调队列
- POJ2823——Sliding Window 单调队列入门
- 【poj】 2823 Sliding Window 单调队列
- 单调队列 - 兼 ACM PKU POJ 3250 及 2823 解题报告
- poj_2823(单调队列)
- POJ 2823 单调队列入门水题
- POJ 2823 Sliding Window(单调队列)
- Sliding Window POJ - 2823 单调队列
- 【单调队列】POJ_2823 Sliding Window