题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23846
题意:问某区间内的众数
思路:主要是练练ST算法,把左右两个不完整的区间剪去后,中间的区间用ST算法一次查询出来。区间的题应该都可以用线段树做。莫名其妙的是,在HDU上交同样的代码就WA
源码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstdlib>
using namespace std;
#define LOCAL
int const MAXN = 100000;
int a[MAXN],dp[MAXN][20],num[MAXN],st[MAXN],en[MAXN],d[MAXN],n,m,total;
int gmax(int a,int b){return a>b?a:b;}
void init()
{
int i,j;
total = 0;
for(i=0; i<n; i++){
scanf("%d",&a[i]);
if(i==0){
st[total] = i;
num[i] = total;
}
else if(a[i]==a[i-1]){
num[i] = total;
}
else{
en[total++] = i-1;
st[total] = i;
num[i] = total;
}
}
en[total] = n-1;
d[0] = 1;
for(i=1; i<n; i++){
if(a[i]!=a[i-1]) d[i] = 1;
else d[i] = d[i-1]+1;
}
for(i=0; i<n; i++) dp[i][0] = d[i];
for(j=1; (1<<(j-1))<=n; j++){
for(i=0; (i+(1<<(j-1)))<n; i++){
dp[i][j] = gmax(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int query(int a,int b)
{
int s1 = num[a]; int s2 = num[b];
if(s1==s2)
return b-a+1;
int l1 = en[s1] - a + 1;
int l2 = b - st[s2] + 1;
// printf("s1 = %d s2 = %d l1 = %d l2 = %d a = %d b = %d\n",s1,s2,l1,l2,a,b);
if(s1==s2-1)
return gmax(l1,l2);
int l3 = 0;
int ss = en[s1]+1;
int ee = st[s2]-1;
int mid = log(ee-ss+1);
l3 = gmax(dp[ss][mid],dp[ee-(1<<mid)+1][mid]);
// while(ss<=ee){
// if(ss==ee){
// l3 = gmax(l3,dp[ss][0]);
// break;
// }
// int mid = log(ee-ss+1);
// l3 = gmax(l3,dp[ss][mid]);
// ss = ss+(1<<mid);
// }
l1 = gmax(l1,l2);
return gmax(l1,l3);
}
int main()
{
#ifdef LOCAL
freopen("data.txt","r",stdin);
freopen("data2.txt","w",stdout);
#endif // LOCAL
while(scanf("%d",&n)!=EOF && n){
scanf("%d",&m);
init();
int i,j;
// printf("left ans right\n");
// for(i=0; i<=total; i++){
// printf("st = %d, en = %d\n",st[i],en[i]);
// }
// printf("num\n");
// for(i=0; i<n; i++)
// printf("%d ",num[i]);
// printf("\n");
// for(i=0; i<n; i++){
// for(j=0; j<20; j++)
// printf("%d ",dp[i][j]);
// printf("\n");
// }
int b,c;
while(m--){
scanf("%d%d",&b,&c);
printf("%d\n",query(b-1,c-1));
}
}
return 0;
}