poj之旅——3368

//好一段时间没弄了,期末考试去了,手都生了。


题目描述:

给出n个非递减序列数,有Q个询问,l,r表示从l到r的出现次数最多的数的出现次数。


题解:

可以为了省空间而浪费编程复杂度——我不喜欢。

介绍一个很简单的方法:

建立一个线段树,维护三个数据maxlen以mid向两边能得到的最大长度,left以l向右能得到的最大长度,right以r向左能得到的最大长度。

用3个if来维护:

a[mid-1]==a[mid]---->maxlen=max(maxlen,lch.right+rch.left)

a[l]==a[mid]-------->left+=rch.left

a[mid-1]==a[r-1]---->right+=lch.right

看似复杂,其实很好理解,这里就不多说了。

另外,用莫队算法可以解决不单调的,可以百度一下。


参考程序:

#include<cstdio>
#include<algorithm>
#define maxn 150000
#define node 3*maxn+1
using namespace std;
int n,T;
int a[maxn];
struct SegMent{
	int left[node],right[node],maxlen[node];
	struct TreeNode{
		int maxlen,left,right;
		operator int(){
			return max(maxlen,max(left,right));
		}
		TreeNode(int maxlen,int left,int right):maxlen(maxlen),left(left),right(right){}
	};
	void build(int p,int l,int r){
		if (l+1==r){
			left[p]=right[p]=maxlen[p]=1;
		}else{
			int pl=2*p,pr=2*p+1;
			int mid=(l+r)>>1;
			build(pl,l,mid);
			build(pr,mid,r);
			maxlen[p]=max(maxlen[pl],maxlen[pr]);
			left[p]=left[pl];right[p]=right[pr];
			if (a[mid-1]==a[mid])
				maxlen[p]=max(maxlen[p],right[pl]+left[pr]);
			if (a[l]==a[mid])
				left[p]+=left[pr];
			if (a[mid-1]==a[r-1])
				right[p]+=right[pl];
		}
	}
	TreeNode query(int p,int ql,int qr,int l,int r){
		if (ql>=r || qr<=l)return TreeNode(0,0,0);else
		if (ql<=l && r<=qr)
			return TreeNode(maxlen[p],left[p],right[p]);
		else{
			int pl=2*p,pr=2*p+1;
			int mid=(l+r)>>1;
			TreeNode lch=query(pl,ql,qr,l,mid),rch=query(pr,ql,qr,mid,r);
			TreeNode tmp(max(lch.maxlen,rch.maxlen),lch.left,rch.right);
			if (a[mid-1]==a[mid])
				tmp.maxlen=max(tmp.maxlen,lch.right+rch.left);
			if (a[l]==a[mid])
				tmp.left+=rch.left;
			if (a[mid-1]==a[r-1])
				tmp.right+=lch.right;
			return tmp;
		}
	}
}tree;
int main(){
	while (scanf("%d%d",&n,&T)==2 && n){
		for (int i=0;i<n;i++)
			scanf("%d",&a[i]);
		tree.build(1,0,n);
		while (T--){
			int from,to;
			scanf("%d%d",&from,&to);
			printf("%d\n",tree.query(1,from-1,to,0,n));
		}
	}
	return 0;
}


还有,将下一程序献给我不屈搏斗又无可奈何Wa的浪费了的时光:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#define maxn 150000
using namespace std;
int n,T;
int a[maxn];
struct Result{
	int maxlen, leftlen, rightlen;
 	operator int(){
		return max(maxlen, max(leftlen, rightlen));
	}
	Result(){}
	Result(int maxlen, int leftlen, int rightlen) : maxlen(maxlen), leftlen(leftlen), rightlen(rightlen){}
};
struct Segment{
	int left[3*maxn+1],right[3*maxn+1];
	Result tree[3*maxn+1];
	void build(int no,int l,int r){
		int mid=(l+r)>>1;
		left[no]=l;right[no]=r;
		if (l+1<r){
			build(2*no,l,mid);
			build(2*no+1,mid,r);
		}
	}
	void replace(int no,int i,int data){
		if (left[no]+1==right[no]){
			tree[no].leftlen=1;
			tree[no].rightlen=1;
			tree[no].maxlen=1;
		}else{
			int mid=(left[no]+right[no])>>1;
			int pl=2*no,pr=2*no+1;
			int l=left[no],r=right[no];
			if (i<mid)replace(pl,i,data);
				else replace(pr,i,data);
			tree[no].maxlen=max(tree[pl].maxlen,tree[pr].maxlen);
			tree[no].leftlen=tree[pl].leftlen;
			tree[no].rightlen=tree[pr].rightlen;
		    if (a[mid-1]==a[mid]){
				tree[no].maxlen=max(tree[no].maxlen,tree[pl].rightlen+tree[pr].leftlen);
			}
			if (a[l]==a[mid]){
				tree[no].leftlen+=tree[pr].leftlen;
			}
			if (a[mid-1]==a[r-1]){
				tree[no].rightlen+=tree[pl].rightlen;
			}
		}
	}
	Result query(int no,int l,int r){
		if (r<=left[no] || right[no]<=l)return Result(0,0,0);else
		if (l<=left[no] && right[no]<=r){
			return Result(tree[no].maxlen,tree[no].leftlen,tree[no].rightlen);
		}else{
			int mid=(left[no]+right[no])>>1;
			Result lch=query(2*no,l,r),rch=query(2*no+1,l,r);
			Result tmp(max(lch.maxlen,rch.maxlen),lch.leftlen,rch.rightlen);
			if (a[mid-1]==a[mid])
				tmp.maxlen=max(tmp.maxlen,lch.rightlen+rch.leftlen);
			if (a[l]==a[mid])tmp.leftlen+=rch.leftlen;
			if (a[mid-1]==a[r-1])tmp.rightlen+=lch.rightlen;
			return tmp;
		}
	}
}Tree;
int main(){
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
	while (scanf("%d%d",&n,&T)==2 && n){
		Tree.build(1,0,n);
		for (int i=0;i<n;i++){
			scanf("%d",&a[i]);
			Tree.replace(1,i,a[i]);
		}
		while (T--){
			int from,to;
			scanf("%d%d",&from,&to);
			printf("%d\n",Tree.query(1,from-1,to));
		}
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值