链接:http://poj.org/problem?id=3368
题目:You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most frequent value among the integers ai , ... , aj.
题意:给一串数字(升序),求任意区间内出现次数最多的数字出现的次数。
分析:靠这道题终于第一次临摹了线段树,虽然没有用到lazy算法。这个线段树的手法不是很标准,因为按照升序排列,所以线段是拍好的,不需要维护修改,所以叶子结点直接存储每个线段的长度,其他节点保存其子孙里最长的线段长度。这样在计算任意区间的时候最多比较三次,左侧的不完全线段,右侧的不完整线段,以及中间完整线段中的最长线段长度(这个用线段树的性质容易得到)。在计算的时候要维护一个前缀和来计算区间端点所在的叶节点位置,以及用来计算左右不完整线段的长度。
题目:You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most frequent value among the integers ai , ... , aj.
题意:给一串数字(升序),求任意区间内出现次数最多的数字出现的次数。
分析:靠这道题终于第一次临摹了线段树,虽然没有用到lazy算法。这个线段树的手法不是很标准,因为按照升序排列,所以线段是拍好的,不需要维护修改,所以叶子结点直接存储每个线段的长度,其他节点保存其子孙里最长的线段长度。这样在计算任意区间的时候最多比较三次,左侧的不完全线段,右侧的不完整线段,以及中间完整线段中的最长线段长度(这个用线段树的性质容易得到)。在计算的时候要维护一个前缀和来计算区间端点所在的叶节点位置,以及用来计算左右不完整线段的长度。
题解:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <string>
#include <cstring>
#include <functional>
#include <cmath>
#include <cctype>
#include <cfloat>
#include <climits>
#include <complex>
#include <deque>
#include <list>
#include <set>
#include <utility>
#define rt return
#define fr freopen("in.txt","r",stdin)
#define fw freopen("out.txt","w",stdout)
#define ll long long
#define ull unsigned long long
#define detie ios_base::sync_with_stdio(false);cin.tie(false);cout.tie(false)
#define pii pair<int,int>
#define lowbit(x) x&(-x)
using namespace std;
#define maxi 0x3f3f3f3f
#define MAX 100010
int v[MAX], sum[MAX];
int n, q, cnt;
struct tree
{
int l, r, m;
tree() {};
tree(int a, int b, int c) {
l = a, r = b, m = c;
}
}a[4 * MAX];
void build(int l, int r, int root)
{
a[root].l = l;
a[root].r = r;
if (l == r)
a[root].m = v[l];
else {
int mid = (l + r) / 2;
build(l, mid, 2 * root);
build(mid + 1, r, 2 * root + 1);
a[root].m = max(a[2 * root].m, a[2 * root + 1].m);
}
}
int querry(int l, int r, int root)
{
if (l <= a[root].l&&a[root].r <= r){
rt a[root].m;
}
else {
int mid = (a[root].l + a[root].r) / 2;
if (r <= mid)rt querry(l, r, 2 * root);
else if (l > mid)rt querry(l, r, 2 * root + 1);
else rt max(querry(l, mid, 2 * root), querry(mid + 1, r, 2 * root + 1));
}
}
int binary_search(int k)
{
int l = 1, r = cnt;
while (l < r)
{
int mid = (l + r) / 2;
if (sum[mid] >= k){
r = mid;
}
else {
l = mid + 1;
}
}
return l;
}
int main()
{
//fr;
detie;
while (~scanf("%d", &n) && n)
{
memset(a, 0, sizeof a);
memset(v, 0, sizeof v);
memset(sum, 0, sizeof sum);
cnt = 0;
scanf("%d", &q);
int pre, num;
pre = maxi;
for (int i = 0; i < n; i++)
{
scanf("%d", &num);
if (num == pre)
v[cnt]++;
else {
v[++cnt]++;
pre = num;
}
}
for (int i = 1; i <= cnt; i++)
{
sum[i] = sum[i - 1] + v[i];
}
build(1, cnt, 1);
while (q--)
{
int i, j, ans;
scanf("%d %d", &i, &j);
int L = binary_search(i);
int R = binary_search(j);
if (L == R)
printf("%d\n", j - i + 1);
else {
ans = max(sum[L] - i + 1, j - sum[R - 1]);
if (L <= R - 2) {
ans = max(ans, querry(L + 1, R - 1, 1));
}
printf("%d\n", ans);
}
}
}
rt 0;
}