题解 UVA11235 【Frequent values】

hicc0305

2018-05-08 10:21:06

Solution

可以注意到,题目中说,这是个非降序序列,也就是说,所有相同的数都是连在一起的!! 所以我们可以把原序列分段,比如样例:-1 -1 1 1 1 1 3 10 10 10 我们可以这样记录:我们把所有相同的数归成一段。用num[p]来记录p这个位置在第几段里,比如num[1]=1,num[2]=1,num[3]=2。然后用l[i]来记录第i段的左边界的序号,r[i]来记录第i段的右边界的序号,比如l[2]=3,r[2]=6。 然后,我们对于每个询问l,r,只需要把l,r分成三个部分求,像这样: ![](https://cdn.luogu.com.cn/upload/pic/18810.png) 然后就转化为了求RMQ,于是我喜欢ST表,于是代码如下。。。 ```cpp #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n,m,cnt=0; int num[500000],l[500000],r[500000],val[500000]; int f[20][500000]; void Clear() { cnt=0; memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); memset(f,0,sizeof(f)); memset(num,0,sizeof(num)); memset(val,0,sizeof(val)); } int main() { while(1) { Clear(); scanf("%d",&n); if(!n) break; scanf("%d",&m); int tmp=-1123645162;//这是乱打的,只要保证第一个x不等于tmp就行。。 for(int i=1;i<=n;i++) { int x; scanf("%d",&x); if(x!=tmp) r[cnt]=i-1,l[++cnt]=i,tmp=x; num[i]=cnt;//处理各个数组 } for(int i=1;i<=cnt;i++) f[0][i]=r[i]-l[i]+1;//预处理f数组 for(int i=1;(1<<i)<=cnt;i++) for(int j=1;j<=n-(1<<i)+1;j++) f[i][j]=max(f[i-1][j],f[i-1][j+(1<<(i-1))]); //ST表求RMQ for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); if(x>y) swap(x,y); if(num[x]==num[y]) printf("%d\n",y-x+1);//如果刚好在一段里,那么直接减一下输出 else { int ans=0; if(num[x]+1<=num[y]-1) { int L=num[x]+1,R=num[y]-1; int k=0; while((1<<(k+1))<=R-L+1) k++; ans=max(f[k][L],f[k][R-(1<<k)+1]); } ans=max(ans,max(r[num[x]]-x+1,y-l[num[y]]+1)); //在三段中取最大 printf("%d\n",ans); } } } return 0; } ```