1. 程式人生 > >Frequent values

Frequent values

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