POJ_3368
本来想找个RMQ问题练一下今天刚学的ST算法,结果这个题我用ST做不出来,所以只好又用回线段树解法了。
当然dicuss里面有人说也可用ST去做的,我就只说一下我用线段树去做的思路吧。
首先,如果a[i]==a[j]的话,自然输出j-i+1就可以了,如果a[i]!=a[j],如果我们直接查询a[i]、a[j]之间的所有整数出现的频率的最大值,显然是有问题的,因为这样可能会将值等于a[i]或a[j]但序号并不在i~j的范围的整数也统计在内。于是,我们便有了一个思路,在统计a[i]、a[j]之间的所有整数出现的频率的最大值之前,能不能修改一下a[i]和a[j]出现的频率,使得可以忽略掉i~j范围之外的但值等于a[i]或a[j]的整数呢?思考一下之后,就会发现这是可以做到的。我们只要用一个数组f[i]记录到第i个整数时,在i及i前面一共有多少个和a[i]相等的整数,这样就可以借助f[i]和f[j]的值修改a[i]和a[j]出现的频率了。
#include<stdio.h>
#include<string.h>
#define D 100001
#define MAXD 200010
#define INF 0x3f3f3f3f
int N, M, Q, tree[4 * MAXD], a[MAXD], f[MAXD];
void build()
{
int i, j, k;
for(i = M; i < 2 * M; i ++)
tree[i] = 0;
for(i = 1; i <= N; i ++)
++ tree[M + a[i]];
for(i = M - 1; i > 0; i --)
tree[i] = tree[2 * i] > tree[2 * i + 1] ? tree[2 * i] : tree[2 * i + 1];
}
void init()
{
int i, j, k, max = -INF;
scanf("%d", &Q);
a[0] = -1;
for(i = 1; i <= N; i ++)
{
scanf("%d", &k);
a[i] = k + D;
if(a[i] > max)
max = a[i];
f[i] = a[i] == a[i - 1] ? f[i - 1] + 1 : 1;
}
for(M = 1; M < max + 2; M <<= 1);
build();
}
void update(int i)
{
for(; i ^ 1; i >>= 1)
tree[i >> 1] = tree[i] > tree[i ^ 1] ? tree[i] : tree[i ^ 1];
}
int search(int i, int j)
{
int max = 0;
for(-- i, ++ j; i ^ j ^ 1; i >>= 1, j >>= 1)
{
if((~i & 1) && tree[i ^ 1] > max)
max = tree[i ^ 1];
if((j & 1) && tree[j ^ 1] > max)
max = tree[j ^ 1];
}
return max;
}
void solve()
{
int i, j, k, x, y, t1, t2;
for(i = 0; i < Q; i ++)
{
scanf("%d%d", &x, &y);
if(a[x] == a[y])
printf("%d\n", y - x + 1);
else
{
t1 = tree[a[x] + M], t2 = tree[a[y] + M];
tree[a[x] + M] = t1 - f[x] + 1;
update(a[x] + M);
tree[a[y] + M] = f[y], update(a[y] + M);
printf("%d\n", search(a[x] + M, a[y] + M));
tree[a[x] + M] = t1, update(a[x] + M);
tree[a[y] + M] = t2, update(a[y] + M);
}
}
}
int main()
{
for(;;)
{
scanf("%d", &N);
if(!N)
break;
init();
solve();
}
return 0;
}