训练指南 P198 例题
在一个非降序数组中寻找区间内出现次数最多的值的出现次数。
用线段树和RMQ都能AC。
RMQ解法
#include <iostream>
#include <cstdio>
#include <cstring>
#define INF 0x7fffffff
using namespace std;
int n;
int a[120000];
int nb[120000],b[120000],bv[120000],l[120000],r[120000],ll[120000],rr[120000];
int d[120000][50];
bool initRMQ()
{
int i,j;
for (i=1; i<=n; i++)
{
d[i][0]=b[i];
}
for (j=1; (1<<j)<=n; j++)
{
for (i=1; i+j-1<=n; i++)
{
d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
}
return true;
}
int queryRMQ(int l,int r)
{
if (r < l)
return 0;
int i;
i=0;
while ((1<<(i+1)) <= r-l+1)
i++;
return max(d[l][i],d[r-(1<<i)+1][i]);
}
int maxx(int a,int b,int c)
{
return max(max(a,b),c);
}
int main()
{
int m,q,i,j,t1,t2;
while (true)
{
scanf("%d",&m);
if (m == 0)
break;
scanf("%d",&q);
n=0;
bv[n]=INF;
for (i=1; i<=m; i++)
{
scanf("%d",a+i);
if (bv[n] != a[i])
{
r[n]=i-1;
n++;
nb[i]=n;
l[n]=i;
b[n]=1;
bv[n]=a[i];
}
else
{
nb[i]=n;
b[n]++;
}
}
r[n]=i-1;
j=0;
for (i=1; i<=m; i++)
{
if (bv[j] != a[i])
j++;
ll[i]=l[j];
rr[i]=r[j];
}
initRMQ();
/* for (i=1; i<=n; i++)
printf("%d ",b[i]);
printf("\n");
for (i=1; i<=n; i++)
printf("%d ",bv[i]);
printf("\n");
for (i=1; i<=n; i++)
printf("%d ",l[i]);
printf("\n");
for (i=1; i<=n; i++)
printf("%d ",r[i]);
printf("\n");
for (i=1; i<=m; i++)
printf("%d ",ll[i]);
printf("\n");
for (i=1; i<=m; i++)
printf("%d ",rr[i]);
printf("\n");
for (i=1; i<=m; i++)
printf("%d ",nb[i]);
printf("\n");*/
while (q--)
{
scanf("%d%d",&t1,&t2);
if (ll[t1] == ll[t2])
{
//printf("1->");
printf("%d\n",t2-t1+1);
}
else
{
// printf("2->");
printf("%d\n",maxx(rr[t1]-t1+1,t2-ll[t2]+1,queryRMQ(nb[rr[t1]+1],nb[ll[t2]-1])));
// printf("%d %d %d %d %d\n",rr[t1]-t1+1,t2-ll[t2]+1,queryRMQ(nb[rr[t1]+1],nb[ll[t2]-1]),nb[rr[t1]+1],nb[ll[t2]-1]);
}
}
}
}
线段树解法
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct T
{
int l;
int r;
int mid;
int flag;
int v;
int lv,rv;
int lc,rc;
};
T tree[1000000];
int cnt[1000000];
int a[1000000];
int n,q;
int min(int a,int b)
{
return a>b?b:a;
}
int max(int a,int b)
{
return a>b?a:b;
}
void buildTree(int l,int r,int c)
{
int t,i;
tree[c].l=l;
tree[c].r=r;
tree[c].mid=(l+r)>>1;
if (l == r)
{
tree[c].v=1;
tree[c].lv=1;
tree[c].rv=1;
tree[c].lc=a[l];
tree[c].rc=a[l];
return ;
}
buildTree(l,tree[c].mid,c<<1);
buildTree(tree[c].mid+1,r,c<<1|1);
tree[c].lv=tree[c<<1].lv;
tree[c].lc=tree[c<<1].lc;
tree[c].rv=tree[c<<1|1].rv;
tree[c].rc=tree[c<<1|1].rc;
tree[c].v=max(tree[c<<1].v,tree[c<<1|1].v);
if (tree[c<<1].rc == tree[c<<1|1].lc)
{
tree[c].v=max(tree[c].v,tree[c<<1].rv+tree[c<<1|1].lv);
if (tree[c<<1].lc == tree[c<<1].rc)
{
tree[c].lv=tree[c<<1].lv+tree[c<<1|1].lv;
tree[c].v=max(tree[c].v,tree[c].lv);
}
if (tree[c<<1|1].lc == tree[c<<1|1].rc)
{
tree[c].rv=tree[c<<1].rv+tree[c<<1|1].rv;
tree[c].v=max(tree[c].v,tree[c].rv);
}
}
}
int query(int l,int r,int c)
{
int t1,t2;
if (tree[c].l == l && tree[c].r == r)
{
return tree[c].v;
}
if (l > tree[c].mid)
return query(l,r,c<<1|1);
else if (r <= tree[c].mid)
return query(l,r,c<<1);
else
{
t1=query(l,tree[c].mid,c<<1);
t2=query(tree[c].mid+1,r,c<<1|1);
if (tree[c<<1].rc != tree[c<<1|1].lc)
{
return t1>t2?t1:t2;
}
else
{
t1=t1>t2?t1:t2;
t2=min(tree[c<<1].rv,tree[c].mid-l+1)+min(tree[c<<1|1].lv,r-tree[c].mid);
return t1>t2?t1:t2;
}
}
}
int main()
{
int i,t1,t2;
while (1)
{
scanf("%d",&n);
if (n == 0)
break;
scanf("%d",&q);
for (i=1; i<=n; i++)
{
scanf("%d",a+i);
}
buildTree(1,n,1);
while (q--)
{
scanf("%d%d",&t1,&t2);
printf("%d\n",query(t1,t2,1));
}
}
}