分塊的概念與運用
【例題1】單點修改+區間查詢
【例題2】區間修改+單點查詢
【例題3】區間修改+區間查詢
【例題4】bzoj 2724 蒲公英
【例題5】bzoj 2038 小z的襪子
通過適當的劃分,預處理一部分資訊並儲存下來。
用空間換取時間,達到時空平衡。易實現。
將查詢區間分成中間整塊+零散兩邊,此時兩部分都在根號n範圍。
簡單來說就是大部分分塊,小部分暴力。
分塊時:塊的大小為根號n,建立每個位置對應的塊的編號。
修改時:直接修改值和相應塊的值。(單點修改)
用getstart函式求出每分塊的第乙個。
注意寫getend函式時,要寫 min(n,getstart[k+1]-1)。
↑↑ getend(4)的正確答案應該是10。
文本版理解
**實現
c
int size = (int)sqrt(n);
int getblock(int x)
int getstart(int b)
int getend(int b)
for(int i = 1; i <= n; i++)
while(q--) else
printf("%d\n", ans);
} else
for(int i = l; i <= getend(getblock(l)); i++)
for(int i = getstart(getblock(r)); i <= r; i++)
printf("%d\n", ans);}}}
solution2這裡不用分塊的方法,是【暴力儲存變化+重構陣列】。
}pair中:修改位置和修改值,用來記錄修改。
【重構】是防止modify很大而維護的定長,c=根號n。
區間加想到差分,轉化為單點修改+區間求和,區間和想到分塊。
#include #include #include #include #include #include #include #include #include using namespace std;
typedef long long ll;
typedef unsigned long long ull;
/*【poj3764】分塊法(區間修改+區間查詢)
如題,已知乙個數列,你需要進行下面兩種操作:
1.將某區間每乙個數加上x; 2.求出某區間每乙個數的和。*/
//整段的修改用標記add處理,不足整段的暴力加和
ll a[100010],sum[100010],add[100010];
int l[100010],r[100010],pos[100010];
int n,m,t;
void change(int l,int r,ll x)
else
}ll ask(int l,int r)
else
return ans;
}int main()//從第乙個數開始,每次分整塊,記錄每塊的編號
if(r[t]#include #include #include #include #include #include #include #include using namespace std;
typedef long long ll;
typedef unsigned long long ull;
長度為n的蒲公英序列,ai表示第i棵蒲公英的種類編號。
m次詢問,每次詢問乙個區間[x,y]裡出現次數最多的種類的編號。
如果次數最多的不止乙個,輸出編號較小的。 */
/*【分析】因為眾數不具有「區間可加性」,考慮分塊。
把序列分成m塊,則每塊長度len=n/m。對於每個詢問的[l,r],
設l處於第p塊,r處於第q塊。我們把區間[l,r]分為三部分:
1.開頭不足一整段的[l,l)。
2.第p+1—q-1塊構成的區間[l,r]。
3.結尾不足一整段的(r,r]。
顯然[l,r]中的眾數隻可能來自於以下兩種情況:
1.區間[l,r]的眾數。2.[l,l)與(r,r]區間內的數(改變了大區間的眾數)。
f[i][j][k]表示第i~j塊中數字k出現的次數,
num[i][j]表示第i~j塊中的眾數,
sum[i][j]表示第i~j塊中眾數出現的次數。
由題意可知a[i]最大能達到1e9,所以必須對資料離散化。
預處理完f、num和sum後。對於每個詢問,可以求得:l屬於p段,r屬於q段。
1.l,r不同段,把首尾多餘的數加入f[p+1][q-1]中更新,再將f[p+1][q-1]還原。
2.l,r同段(或在相鄰段),把l~r的數加入到f[0][0]中更新,再將f[0][0]還原。 */
const int max=40100;
int n,m,len,q,maxsum,maxnum,ans,ll,rr,tot;
int a[max],b[max],c[max],l[max],r[max];
int f[40][40][max],sum[40][40],num[40][40];
//f[i][j][k]表示第i~j塊中數字k出現的次數,
//num[i][j]表示第i~j塊中的眾數,
//sum[i][j]表示第i~j塊中眾數出現的次數。
inline int get_int()
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}inline void pre()
for(int i=m;i>=1;i--) if(y>=l[i])
if(l+1<=r-1)
else ll=rr=0; //l,r同段(或相鄰段),則將l~r的數加入到f[0][0]中更新
maxsum=sum[ll][rr]; maxnum=num[ll][rr];
if(l==r)
else
return c[maxnum];
}int main(){
n=get_int(); q=get_int();
for(int i=1;i<=n;i++) a[i]=get_int();
pre(); //預處理
while(q--){
int x=get_int(),y=get_int();
ans=solve((x+ans-1)%n+1,(y+ans-1)%n+1);
cout<——時間劃過風的軌跡,那個少年,還在等你。一鍵回頂
暖 墟 資料結構高階 2 SAT問題
使用強連通分量。對於每個變數 x,建立兩個點 x,x 分別表示變數 x取true和取false。圖的節點個數是兩倍的變數個數。在儲存方式上,可以給第 i個變數標號為 i,其對應的反值標號為 i n 對於每個要求 a b 轉換為 a b b a 即 若 a假則 b 必真,若 b 假則 a 必真 然後按...
2019 9 25 初級資料結構 樹狀陣列
一 樹狀陣列基礎 學oi的同學都知道,位運算 對二進位制的運算 比普通運算快很多。同時我們接觸到了狀態壓縮的思想 即將0 1的很多個狀態壓縮成十進位制的乙個數,每乙個二進位制位表示乙個狀態 由於在實際做題過程當中,由於資料範圍限制,我們必須採用更高效的儲存 查詢方法,於是樹狀陣列應運而生。首先我們檢...
塊狀資料結構 分塊
分塊演算法實質上是一種是通過分成多塊後在每塊上打標記以實現快速區間修改,區間查詢的一種演算法。其均攤時間複雜度為o n o sqrt n o n 分塊演算法相較於各種高階資料結構,具有簡便易寫,方便除錯等多種優點。在同等資料規模下,如 1e5 1e51e 5 其時間效率並不會低太多,在很多時反而是一...