分塊之區間修改與單點查詢

来源:http://www.cnblogs.com/zwfymqz/archive/2017/05/19/6879187.html
-Advertisement-
Play Games

給出一個長為n的數列,以及n個操作,操作涉及區間加法,單點查值。 這是一道能用許多數據結構優化的經典題,可以用於不同數據結構訓練。 數列分塊就是把數列中每m個元素打包起來,達到優化演算法的目的。 以此題為例,如果我們把每m個元素分為一塊,共有n/m塊,每次區間加的操作會涉及O(n/m)個整塊,以及區間 ...


給出一個長為n的數列,以及n個操作,操作涉及區間加法,單點查值。

 

這是一道能用許多數據結構優化的經典題,可以用於不同數據結構訓練。

數列分塊就是把數列中每m個元素打包起來,達到優化演算法的目的。

 

以此題為例,如果我們把每m個元素分為一塊,共有n/m塊,每次區間加的操作會涉及O(n/m)個整塊,以及區間兩側兩個不完整的塊中至多2m個元素。

我們給每個塊設置一個加法標記(就是記錄這個塊中元素一起加了多少),每次操作對每個整塊直接O(1)標記,而不完整的塊由於元素比較少,暴力修改元素的值。

每次詢問時返回元素的值加上其所在塊的加法標記。

這樣每次操作的複雜度是O(n/m)+O(m),根據均值不等式,當m取√n時總複雜度最低,為了方便,我們都預設下文的分塊大小為√n。

 

區間加法

 1 void interval_add(int ll,int rr,int v)
 2 {
 3     for(int i=ll;i<=min(where[ll]*m,rr);i++)
 4     //這裡判斷的是where[ll]是不完全塊的情況,也就是ll在他實際塊最左端的右側,
 5     // 然後便利ll-所在塊的結尾/rr,暴力增加 
 6         a[i]+=v; 
 7     if(where[ll]!=where[rr])
 8     // 註意如果是ll和rr在一個塊中的話,上面已經加過一邊,所以不用加 
 9     {
10         for(int i=(where[rr]-1)*m;i<=rr;i++)
11         // 這裡判斷的是rr在他實際所在塊的最右端左側的情況
12         // where[i]*m表示的是第i個塊最右端的元素
13         // where[rr]-1就是rr所在塊左邊那個塊最右端的元素
14         // 一直到rr暴力增加 
15             a[i]+=v;    
16     }    
17     for(int i=where[ll]+1;i<=where[rr]-1;i++)
18     //這裡where[ll]和where[rr]均已暴力處理過,所以只枚舉中間的塊就可以 
19         add[i]+=v;
20 } 

單點查詢

 1 printf("%d\n",a[v]+add[where[v]]); 

 

完整代碼

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 const int MAXN=100001;
 7 int n,q,m,how,l,r,v;
 8 int a[MAXN];// 初始值
 9 int add[MAXN];// 後來每個塊上加入的值
10 int where[MAXN];// 記錄每一個值對應第幾塊
11 void interval_add(int ll,int rr,int v)
12 {
13     for(int i=ll;i<=min(where[ll]*m,rr);i++)
14     //這裡判斷的是where[ll]是不完全塊的情況,也就是ll在他實際塊最左端的右側,
15     // 然後便利ll-所在塊的結尾/rr,暴力增加 
16         a[i]+=v; 
17     if(where[ll]!=where[rr])
18     // 註意如果是ll和rr在一個塊中的話,上面已經加過一邊,所以不用加 
19     {
20         for(int i=(where[rr]-1)*m;i<=rr;i++)
21         // 這裡判斷的是rr在他實際所在塊的最右端左側的情況
22         // where[i]*m表示的是第i個塊最右端的元素
23         // where[rr]-1就是rr所在塊左邊那個塊最右端的元素
24         // 一直到rr暴力增加 
25             a[i]+=v;    
26     }    
27     for(int i=where[ll]+1;i<=where[rr]-1;i++)
28     //這裡where[ll]和where[rr]均已暴力處理過,所以只枚舉中間的塊就可以 
29         add[i]+=v;
30 } 
31 int main()
32 {
33     scanf("%d",&n);
34     m=sqrt(n);
35     for(int i=1;i<=n;i++)
36         scanf("%d",&a[i]);
37     for(int i=1;i<=n;i++)
38         where[i]=(i-1)/m+1;// 這裡的i可以-1(hzwer寫的是-1)也可以不寫,不寫的話第一塊的元素個數會是m-1 
39     scanf("%d",&q);
40     for(int i=1;i<=q;i++)
41     {
42         scanf("%d",&how);
43         if(how==1)// 區間加
44         {
45             scanf("%d%d%d",&l,&r,&v);
46             interval_add(l,r,v);
47         }
48         else// 單點查詢 
49         {
50             scanf("%d",&v);
51             printf("%d\n",a[v]+add[where[v]]);
52             // where保存的是這個點所屬的塊,add表示這個塊已經增加的元素
53             //a[v]是這個點開始的值,一加就是答案 
54         } 
55     }
56     return 0;
57 }

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 給出一個長為n的數列,以及n個操作,操作涉及區間加法,區間求和。 這題的詢問變成了區間上的詢問,不完整的塊還是暴力;而要想快速統計完整塊的答案,需要維護每個塊的元素和,先要預處理一下。 考慮區間修改操作,不完整的塊直接改,順便更新塊的元素和;完整的塊類似之前標記的做法,直接根據塊的元素和所加的值計算 ...
  • 顯然我們一定是先走到AB上一點X,然後走到CD上一點Y,最後到D。 那麼答案就是|AX|/P+|XY|/R+|YD|/Q 假設我們已經確定了X,那麼目標就是在CD上找一點Y,使|XY|/R+|YD|/Q最小。 顯然這是個單峰函數。 那麼三分套三分就可以了。 代碼: #include<iostream ...
  • 結構型模式是描述如何將類對象結合在一起,形成一個更大的結構,結構模式描述兩種不同的東西:類與類的實例。故可以分為類結構模式和對象結構模式。在GoF設計模式中,結構型模式有:1.適配器模式 Adapter 適配器模式是將一個類的介面轉換成客戶希望的另外一個介面。適配器模式使得原本由於介面不相容而不能一 ...
  • (filetype("./test")); //判斷是文件還是目錄 * (is_file("./aa.txt")); //判斷是否是文件 * is_dir("./test"); //判斷是否是目錄 echo fileatime("./aa.txt"); //文件的上次訪問時間 返回時間戳 echo ... ...
  • 一、random常用模塊 1.random.random() 隨機生成一個小數 2.random.randint(m,n) 隨機生成一個m到n的整數(包括n) 3. random.randrange(m,n) 隨機生成m到n中的一個數,包括 m 但是不包括 n 4. random.smaple(so ...
  • 1 <bean name="u" class="com.bjsxt.dao.impl.UserDAOImpl"></bean> 1 <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl"></bean> 用id和name的效果是一樣的,唯一的不同是 n ...
  • Ant path 匹配原則 在Spring MVC中經常要用到攔截器,在配置需要要攔截的路徑時經常用到<mvc:mapping/>子標簽,其有一個path屬性,它就是用來指定需要攔截的路徑的。例如: <mvc:interceptor><mvc:mapping path="/**" /><bean c ...
  • PHP中include和require關鍵字,都可以在一個腳本文件中包含另一個腳本文件,但是兩者卻有幾點不同處: 1.include包含文件,出錯時會產生一個E_WARNING(警告),但是腳本仍舊可以繼續運行 2.require包含文件,會產生一個E_COMPILE_ERROR(錯誤),腳本終止 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...