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

来源: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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...