C. Optimal Insertion 題解(莫隊 區間眾數問題)
阿新 • • 發佈:2021-10-26
分塊
分塊
先看我們線上段樹, 樹狀陣列中說爛了的模板題
Description
給定一個長度為 \(N\) 的數列 \(A\) ,以及 \(M\) 條指令,每條指令可能是以下兩種之一:
C l r d
,表示把 \(A[l],A[l+1],…,A[r]\) 都加上 \(d\) 。
Q l r
,表示詢問數列中第 \(l∼r\) 個數的和。
對於每個詢問,輸出一個整數表示答案。
顧名思義, 分塊非常形象的理解就是分成一塊一塊。
對於零碎的塊, 我們暴力解決。
對於完整的塊, 我們直接加就好了。
分塊
int get(int x)
{
return x/ len;
}
len= sqrt(n); //len是塊的長度 for(int i= 1; i<= n; i++ ) scanf("%d", &a[i]); for(int i= 1; i<= n; i++ ) s[get(i)]+= a[i], siz[get(i)]++ ; //s表示和, 也就是我們記錄的資訊
修改
void change(int l, int r, int d) { if(get(l)== get(r)) { for(int i= l; i<= r; i++ ) a[i]+= d, s[get(i)]+= d; return ; } int i= l, j= r; while(get(i)== get(l)) a[i]+= d, s[get(i)]+= d, i++ ; //找到整的塊 while(get(j)== get(r)) a[j]+= d, s[get(j)]+= d, j-- ; for(int k= get(i); k<= get(j); k++ ) s[k]+= (ll)siz[k]* d, add[k]+= d; //add是類似懶標記的東西, 有些時候不用一個個加 return ; }
查詢
未來可期。//可以發現是上面的改改。 ll query(int l, int r) { if(get(l)== get(r)) { ll ans= 0; for(int i= l; i<= r; i++ ) ans+= (ll)a[i]+ add[get(i)]; return ans; } ll ans= 0; int i= l, j= r; while(get(i)== get(l)) ans+= (ll)a[i]+ add[get(i)], i++ ; while(get(j)== get(r)) ans+= (ll)a[j]+ add[get(j)], j-- ; for(int k= get(i); k<= get(j); k++ ) ans+= s[k]; return ans; }