整理的算法模板:ACM算法模板總結(分類詳細版)
從前有個人名叫 WNB,他有着天才般的記憶力,他珍藏了許多許多的寶藏。
在他離世之後留給後人一個難題(專門考驗記憶力的啊!),如果誰能輕鬆回答出這個問題,便可以繼承他的寶藏。
題目是這樣的:給你一大串數字(編號爲 11 到 NN,大小可不一定哦!),在你看過一遍之後,它便消失在你面前,隨後問題就出現了,給你 MM 個詢問,每次詢問就給你兩個數字 A,BA,B,要求你瞬間就說出屬於 AA 到 BB 這段區間內的最大數。
一天,一位美麗的姐姐從天上飛過,看到這個問題,感到很有意思(主要是據說那個寶藏裏面藏着一種美容水,喝了可以讓這美麗的姐姐更加迷人),於是她就竭盡全力想解決這個問題。
但是,她每次都以失敗告終,因爲這數字的個數是在太多了!
於是她請天才的你幫他解決。如果你幫她解決了這個問題,可是會得到很多甜頭的哦!
輸入格式
第一行一個整數 NN 表示數字的個數。
接下來一行爲 NN 個數,表示數字序列。
第三行讀入一個 MM,表示你看完那串數後需要被提問的次數。
接下來 MM 行,每行都有兩個整數 A,BA,B。
輸出格式
輸出共 MM 行,每行輸出一個數,表示對一個問題的回答。
數據範圍
1≤N≤2×1051≤N≤2×105,
1≤M≤1041≤M≤104
輸入樣例:
6
34 1 8 123 3 2
4
1 2
1 5
3 4
2 3
輸出樣例:
34
123
123
8
區間查詢最大值,並且是離線靜態的,很明顯用ST表,存儲時間複雜度 O(nlogn),查詢速度O(1);
如果用線段樹,存儲和查詢的時間複雜度都是 O(nlogn);但是這道題數據比較水,都能過;
ST表:
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+7,M=20;
int dp[N][M],a[N];
int main()
{
int n;
cin >>n;
for(int i=1;i<=n;i++) cin >>a[i];
for(int j=0;j<M;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
if(!j) dp[i][j]=a[i];
else dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
int q;
cin >>q;
while(q--)
{
int a,b;
cin >>a>>b;
int res=log(b-a+1)/log(2);
cout <<max(dp[a][res],dp[b-(1<<res)+1][res])<<endl;
}
}
線段樹:
#include <bits/stdc++.h>
using namespace std;
const int N=2*100005;
int w[N];//區間裏的數
int n,m;
struct node
{
int l,r; //當前結點所處區間
int maxx;
}tr[N*4];//注意對題中所給操作數量或者數據要開4倍大
void pushup(int u)// 由子節點更新父節點
{
tr[u].maxx=max(tr[u<<1].maxx,tr[u<<1|1].maxx);
}
void build(int u,int l,int r)
{
if(l==r) tr[u]={l,r,w[r]};//如果處理到葉結點了,就保存葉結點的信息
else
{ tr[u]={l,r}; //保存當前節點的區間信息
int mid=l+r>>1;
build(u<<1,l,mid); //遞歸左節點
build(u<<1|1,mid+1,r); // 遞歸右節點
pushup(u); //每次根據子節點更新父節點
}
}
node query(int u,int l,int r) //在區間l,r裏面查詢
{
if(tr[u].l>=l&&tr[u].r<=r) return tr[u]; // 如果當前區間在l~r裏面,則直接返回想要的信息
else
{
int mid=tr[u].l+tr[u].r>>1; //取當前節點的區間中點
if(r<=mid) return query(u<<1,l,r); // 如果當前查詢區間在當前區間的中點左端,則遞歸左兒子
else if(l>mid) return query(u<<1|1,l,r); //如果當前查詢區間在當前節點區間的右端,則遞歸右兒子;
else //如果一部分在mid左邊,一部分在mid右邊
{
auto left=query(u<<1,l,r); //遞歸左兒子
auto right=query(u<<1|1,l,r); //遞歸右兒子
node res;
res.maxx=max(left.maxx,right.maxx) ; //由左兒子和右兒子的信息來更新當前父節點的信息
return res;
}
}
}
int main()
{
int n;
cin >>n;
for(int i=1;i<=n;i++) cin >>w[i];
build(1,1,n);
int m;
cin >>m;
for(int i=0;i<m;i++)
{
int l,r;
cin >>l>>r;
cout <<query(1,l,r).maxx<<endl;
}
}