您的位置:首页 > 产品设计 > UI/UE

单调队列学习小记 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

//单调队列
#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: