题目链接:http://poj.org/problem?id=3368
题目大意:给你一段不下降的序列,求给定区间里出现次数最多的那个数字的次数。
思路:首先看到这题时,第一感觉线段树,但是仔细一看问题来啦,用线段数我怎么才能计算出某段区间里出现的那个数,因为出现最多的那个数可能不是在他它的左儿子上也不是在它的右儿子上,可能在当他们合并成一个区间时就出现啦,但是这儿我们需要注意的就是,题目给的是一段不下降的序列,那么突破口就出来啦,因为如果出现相同的数字,那么它们一定是连续的。所以我们只需要在普通的线段树中加上两个变量用来记录这段区间他的最左边那个数连续数的个数和在最右边那个数连续的个数。在我们求这段区间最大次数,需要多做一次比较(在这段区间的两个子区间中,当左子区间最右边数和右区间最左边的数相等时,取三个数的最大值)。。。。。
code:
#include<cstdio> #include<cmath> #include<algorithm> #include<iostream> #define Max 100010 using namespace std; struct Node { int l,r; int amax,lmaxm,rmax; //amax用来记录这段区间出现最多的次数的个数,lmax用来记录最左边那个数在这段区间连续的个数,rmax用来记录最右边那个数在这段区间连续的个数 }node[Max*4]; int a[Max]; void build(int u,int l,int r) { node[u].l=l; node[u].r=r; if(l==r) { node[u].amax=node[u].lmaxm=node[u].rmax=1; return; } int mid=(l+r)/2; build(u*2,l,mid); build(u*2+1,mid+1,r); int tem; if(a[node[u*2].r]==a[node[u*2+1].l]) { tem=node[u*2].rmax+node[u*2+1].lmaxm; } else { tem=0; } node[u].amax=max(max(node[u*2].amax,node[u*2+1].amax),tem); node[u].lmaxm=node[u*2].lmaxm; //大区间的最左边的那个数和左子区间那个数值相同的 if(node[u*2].lmaxm==mid-l+1&&a[node[u*2].r]==a[node[u*2+1].l]) //判断左子区间里的数是否相同并且和右子区间最左边那个数相同,相同则大区间lmax需要变化 { node[u].lmaxm+=node[u*2+1].lmaxm; } node[u].rmax=node[u*2+1].rmax; //<span style="font-family: Arial, Helvetica, sans-serif;">大区间的最右边的那个数和右子区间那个数值相同的</span> if(node[u*2+1].rmax==r-mid&&a[node[u*2].r]==a[node[u*2+1].l]) <span style="font-family: Arial, Helvetica, sans-serif;">//判断右子区间里的数是否相同并且和左子区间最右边那个数相同,相同则大区间rmax需要变化</span> { node[u].rmax+=node[u*2].rmax; } } int query(int u,int l,int r) { if(node[u].l==l&&node[u].r==r) { return node[u].amax; } int mid=(node[u].l+node[u].r)/2; if(r<=mid) return query(u*2,l,r); else if(l>mid) return query(u*2+1,l,r); else { int a1=query(u*2,l,mid); int a2=query(u*2+1,mid+1,r); int a3=0; if(a[node[u*2].r]==a[node[u*2+1].l]) //比较 { a3=min(node[u*2].rmax,mid-l+1)+min(node[u*2+1].lmaxm,r-mid); } return max(max(a1,a2),a3); } } int main() { int n,p,x,y,i; while(scanf("%d",&n)==1) { if(n==0) break; scanf("%d",&p); for(i=1;i<=n;i++) { scanf("%d",&a[i]); } build(1,1,n); for(i=0;i<p;i++) { scanf("%d%d",&x,&y); printf("%d\n",query(1,x,y)); } } return 0; }
poj 3368 Frequent values(线段树解法),布布扣,bubuko.com
poj 3368 Frequent values(线段树解法)
原文地址:http://blog.csdn.net/u010304217/article/details/38276463