题意:一个长度为n的数组,进行m次询问,每次询问给出一个区间,求出这个区间中的数出现的最多的次数
题目链接:http://poj.org/problem?id=3368
思路:线段树,区间合并
如下:
线段树中的节点记录出现的最左边的数和次数,以及最右边的数和次数,
在合并的时候,如下两个区间
[s,m] [m+1,t]
那么需要看val[m] 和val[m+1] 的值是不是相同,
不相同的话,直接合并即可,
否则,
那么左边和最右边的值和次数均会发生改变,进行比较
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define maxn 100010
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct segnode{
int lnum,rnum,num;
};
segnode tree[maxn<<2];
int val[maxn];
void build(int l,int r,int rt){
if(l == r){
tree[rt].lnum = 1;
tree[rt].rnum = 1;
tree[rt].num = 1;
return ;
}
int m = (l + r)/2;
build(lson);
build(rson);
if(val[m] == val[m+1]){
if(val[l] == val[m + 1])
tree[rt].lnum = tree[rt<<1].lnum + tree[rt<<1|1].lnum;
else tree[rt].lnum = tree[rt<<1].lnum;
if(val[m] == val[r])
tree[rt].rnum = tree[rt<<1|1].rnum + tree[rt<<1].rnum;
else tree[rt].rnum = tree[rt<<1|1].rnum;
tree[rt].num = max(tree[rt<<1].num,max(tree[rt<<1|1].num, tree[rt<<1].rnum + tree[rt<<1|1].lnum));
}
else{
tree[rt].lnum = tree[rt<<1].lnum;
tree[rt].rnum = tree[rt<<1|1].rnum;
tree[rt].num = max(tree[rt<<1].num , tree[rt<<1|1].num);
}
}
int query(int L,int R,int l,int r,int rt){
if(L <= l && r <= R){
return tree[rt].num;
}
int m = (l + r)/2;
if(R <= m) return query(L,R,lson);
else if(L > m) return query(L,R,rson);
else{
int lans = query(L,m,lson);
int rans = query(m+1,R,rson);
if(val[m] == val[m+1]){
int temp = min(tree[rt<<1].rnum , m - L + 1) + min(tree[rt<<1|1].lnum , R - m);
return max(temp,max(lans,rans));
}
else{
return max(lans,rans);
}
}
}
int main()
{
int n,m,a,b;
while(~scanf("%d",&n) && n){
scanf("%d",&m);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]);
build(1,n,1);
while(m--){
scanf("%d %d",&a,&b);
if(a==b) printf("1\n");
else
printf("%d\n",query(a,b,1,n,1));
}
}
return 0;
}