POJ 3368 Frequent values(线段树+离散化)
思路:
首先对给出的序列进行离散化统计,将相同的数字压缩成一个节点,然后统计出这个压缩后的节点在原序列中起点和终点的位置,以及出现的次数等。当然也要记录原数字在离散化后的序列中的位置。
之后就是查询,比方说[a,b]
1.如果a,b属于同一个组,那么区间长度就是我们想要的答案 b-a+1;
2.如果a,b组号相差1,说明该区间被中间截断了,只要分别研究两侧的区间,取大值即可Max(c-a+1,b-c) ---其中c是中间点---
3.如果a,b组号相差大于1,先取出两侧进行研究,取大值,然后再用线段树,算出中间区间的最大值,与刚才的那个数比较,取出最大值即可。
#include <iostream> #include <cstdio> using namespace std; const int MAXN = 100005; struct Point { int left; int right; int num; int count; }p[MAXN]; int n, q, t, len; int a[MAXN], hash[MAXN]; struct SegNode { int left; int right; int num; int count; SegNode* lchild; SegNode* rchild; void Build(int l, int r); int Query(int l, int r); }tree[MAXN*2], *root = tree; void Init() { int i; for (i = 1; i <= n; i++) scanf("%d", &a[i]); p[1].left = 1; p[1].right = 1; p[1].num = a[1]; p[1].count = 1; hash[1] = 1; for (t = 1, i = 2; i <= n; i++) { if (a[i] == a[i-1]) { p[t].count++; p[t].right = i; } else { t++; p[t].left = i; p[t].right = i; p[t].num = a[i]; p[t].count = 1; } hash[i] = t; } } void SegNode::Build(int l, int r) { left = l; right = r; if (left == right) { num = p[left].num; count = p[left].count; lchild = rchild = NULL; return; } int mid = (l+r)>>1; lchild = &tree[len++]; lchild->Build(l, mid); rchild = &tree[len++]; rchild->Build(mid+1, r); if (lchild->count > rchild->count) { num = lchild->num; count = lchild->count; } else { num = rchild->num; count = rchild->count; } } int SegNode::Query(int l, int r) { if (l == left && r == right) return count; int mid = (left+right) >> 1; if (r <= mid) return lchild->Query(l, r); else if (l > mid) return rchild->Query(l, r); else { int tl = lchild->Query(l, mid); int tr = rchild->Query(mid+1, r); return tl > tr ? tl : tr; } } int Solve(int a, int b) { if (hash[a] == hash[b]) return b-a+1; else if (hash[a]+1 == hash[b]) { int ta = p[hash[a]].right - a + 1; int tb = b - p[hash[b]].left + 1; return ta > tb ? ta : tb; } else { int ta = p[hash[a]].right - a + 1; int tb = b - p[hash[b]].left + 1; int qy = root->Query(hash[a]+1, hash[b]-1); int ans = ta > tb ? ta : tb; return ans > qy ? ans : qy; } } int main() { int a, b; while (scanf("%d", &n) != EOF, n) { scanf("%d", &q); Init(); len = 1; root->Build(1, t); while (q--) { scanf("%d%d", &a, &b); printf("%d\n", Solve(a, b)); } } }