1. 程式人生 > >UVA 11235 Frequent values (RMQ )

UVA 11235 Frequent values (RMQ )

代碼 分段 mem 結果 using 編號 stream tput include

題意:給出一個非降序的序列,你的任務是對於一系列詢問(i,j),回答在這個區間內出現最多的數的次數。

Sample Input

10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0

Sample Output

1
4
3

思路:將數字分段,相同的為一段,用value[i]和c[i]分別表示第i段的數值和出現次數,num[p],Lefe[p],
    Right[p]分別表示位置p所在段的編號和左右端點位置,每次查詢(L,R)的結果為以下三個數的最大值:
    從L到L所在段的結束處的元素個數(Right[L]-L+1),從R所在段的開始處到R處的元素個數(R-Left[R]+1),
    中間第num[L]+1段到第num[R]-1段的c的最大值(這裏可以用RMQ來算)。
    特殊情況:如果L和R在同一段,那麽答案就是R-L+1;如果L和R是相鄰段,那麽答案是前兩個數的較大值。
    (代碼中輸入是從1開始的,還沒有交測評,vj進不去23333,要是錯了再來改)

代碼:
#include<iostream>
#include<string.h>
using namespace std;
const int maxn=1e5+5;

int a[maxn],value[maxn],c[maxn],num[maxn],Left[maxn],Right[maxn],d[maxn][20],n,q;
void init(){
int op=1;
for(int i=1;i<=n;i++){
if(i==1){
value[op]=a[i];
c[op]++;
num[i]=op;
Left[i]=i;
}
else {
if(a[i]==a[i-1]){
c[op]++;
num[i]=num[i-1];
Left[i]=Left[i-1];
}
else {
value[++op]=a[i];
c[op]++;
num[i]=op;
Left[i]=i;
int k1=i-1,k2=a[i-1],j=i-1;
while(a[j]==k2&&j>=1)Right[j]=k1,j--;
}
}
}
memset(d,0,sizeof(d));
for(int i=1;i<=op;i++)d[i][0]=c[i];
for(int j=1;(1<<j)<=op+1;j++){
for(int i=0;i+(1<<j)-1<=op;i++){
d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int l,int r){
int k=0;
while((1<<(k+1))<=r-l+1)k++;
return max(d[l][k],d[r-(1<<k)+1][k]);
}
int main(){
while(cin>>n){
if(n==0)break;
cin>>q;
for(int i=1;i<=n;i++)cin>>a[i];
init();
int l,r,sum=0;
for(int i=0;i<q;i++){
cin>>l>>r;
if(num[l]==num[r])cout<<r-l+1<<endl;
else {
//cout<<Right[l]<<‘ ‘<<Left[r]<<endl;
sum=max(Right[l]-l+1,r-Left[r]+1);
int x=num[l]+1,y=num[r]-1;
if(x>y)cout<<sum<<endl;
else {
sum=max(sum,RMQ(x,y));
cout<<sum<<endl;
}
}
}
}
return 0;
}

UVA 11235 Frequent values (RMQ )