1. 程式人生 > 實用技巧 >AcWing802區間和

AcWing802區間和

題目地址https://www.acwing.com/problem/content/804/

題目描述

假定有一個無限長的數軸,數軸上每個座標上的數都是0。

現在,我們首先進行 n 次操作,每次操作將某一位置x上的數加c。

接下來,進行 m 次詢問,每個詢問包含兩個整數l和r,你需要求出在區間[l, r]之間的所有數的和。

輸入格式

第一行包含兩個整數n和m。

接下來 n 行,每行包含兩個整數x和c。

再接下里 m 行,每行包含兩個整數l和r。

輸出格式

共m行,每行輸出一個詢問中所求的區間內數字和。

資料範圍

1e9x1e9
1n,m1e5
1e9lr1e9


10000c10000

題解:通過觀察這道題,我們不難看出這就是一道區間字首和的問題,但是不同在於這裡面的下標的範圍比較大,1e9,對於比賽而言不會有這麼大的儲存空間的,但是我們發現這裡最多隻有n+2*m個不同的數(在[-1e9,1e9]之間),所以實際只有n+2*m個有效的數字,那麼便會顯而易見的想到了離散化。但是初始的時候,我只是將n個數字進行離散化,後來的2*m的數字沒有離散化,那麼在後面的求解的過程中就遇到了一些問題,雖然也能解決,但是就比較麻煩了,醉蛛要的是非常容易出錯。

AC程式碼

#include<bits/stdc++.h>
using namespace
std; const int N=3e5+10; vector<int>all; pair<int,int>pa[N]; int n,m,a[N]={0},sum[N]={0}; int find(int x){//找到等於x離散化後的下標,從1開始,1 2 3 ... n int l=0,r=all.size()-1; while(l<r){ int mid=l+r>>1; if(all[mid]>=x) r=mid; else l=mid+1; } return r+1
; } int main(){ cin>>n>>m; for(int i=1,x,c;i<=n;i++){ cin>>x>>c; pa[i].first=x; pa[i].second=c; all.push_back(x); } for(int i=n+1;i<=n+m;i++){ cin>>pa[i].first>>pa[i].second; all.push_back(pa[i].first); all.push_back(pa[i].second); } sort(all.begin(),all.end()); all.erase(unique(all.begin(),all.end()),all.end()); for(int i=1;i<=n;i++){ int x=find(pa[i].first); a[x]+=pa[i].second; } for(int i=1;i<=all.size();i++) sum[i]=sum[i-1]+a[i]; for(int i=n+1;i<=n+m;i++){ int fx=find(pa[i].first); int fy=find(pa[i].second); cout<<sum[fy]-sum[fx-1]<<endl; } return 0; }

寫於:202/8/23 12:56