Frequent values
阿新 • • 發佈:2018-03-08
req std 現在 連續 容易 nlogn 返回 val 次方
↑這是題面,趙老師%%%
我們很容易就能想到縮點。將連續的一段數字縮為一個點。然後在點上跑st表。
類似於分塊的想法
如果有零碎的塊,就暴力計算。中間的塊使用st表O(1)計算
總時間復雜度(nlogn)
O(n)分塊。
O(nlogn)預處理。
O(1)查詢。
#include<iostream>
#include<cstdio>
using namespace std;
int in[100000],n;
struct node
{
int x;
int y;
int len;
};//塊的結構體
node k[1000000];//塊
int ll;//塊的個數
int st[1000010][20];//在塊上的st表
int log[1000010];//以2為底的log
int pow[20];//二的n次方
int flag[1000010];//原數組中第i項屬於第幾個塊
void st_()//st表初始化
{
log[0]=0;
log[1]=0;
for(int i=2;i<=ll;i++)
log[i]=log[i>>1]+1;//遞推log
pow[0]=1;
for(int i=1;i<=log[ll];i++)
pow[i]=pow[i-1]<<1;//處理2^N次方
for(int i=1 ;i<=ll;i++)
st[i][0]=k[i].len;
for(int i=1;i<=log[ll];i++)//正常的st表
for(int j=1;j+pow[i]-1<=ll;j++)
st[j][i]=max(st[j][i-1],st[j+pow[i-1]][i-1]);
}
void first_work()//分塊
{
int now=-0x7fffffff;
for(int i=1;i<=n;i++)
{
if(now!=in[i])//分塊。遇到一個不同於當前的數據。則表示要進行下一步的分塊
{
k[ll].y=i-1;//前一個塊的右節點
k[ll].len=k[ll].y-k[ll].x+1;//前一個塊的長度
k[++ll].x=i;//現在塊的左節點
now=in[i];//更新
}
flag[i]=ll;//處理第i項在那一塊裏
}
k[ll].y=n;
k[ll].len=k[ll].y-k[ll].x+1;
}
int st_check(int begin,int end)//連續的塊查詢。
{
if(begin>end)//這種情況發生在兩個零塊相鄰。所以中間沒有整塊
return -0x7fffffff;//返回無窮小
int l=end-begin+1;
return max(st[begin][log[l]],st[end-pow[log[l]]+1][log[l]]);//O(1)查詢
}
int bl_check(int begin,int end)//零塊查詢
{
return end-begin+1;//直接計算,因為一個塊中沒有不同的數字
}
int main()
{
scanf("%d",&n);
int m;
scanf("%d",&m);
for(int i=1;i<=n;i++)
scanf("%d",&in[i]);
first_work();
st_();
int a,b;
int ans;
for(int i=1;i<=m;i++)
{
ans=-0x7ffffff;
scanf("%d%d",&a,&b);
ans=max(ans,bl_check(a,k[flag[a]].y));//分成兩個零塊和一堆連續的整塊
ans=max(ans,st_check(flag[a]+1,flag[b]-1));
ans=max(ans,bl_check(k[flag[b]].x,b));
printf("%d\n",ans);
}
}
Frequent values