其實這題還可以用值域線段樹來做的。。。
考慮到 \([-1e9,1e9]\) 的資料範圍,則一般的線段樹絕對會MLE,但同時我們注意到點的個數只有 \(2e5\) 個,考慮使用動態開點線段樹。
即對於每個村莊,看做一個點,所以我們的線段樹無需模擬滿二叉樹。
由於 \(log_2(2e9)\approx30\) ,所以我們的線段樹陣列需要至少開到 \(30 \times 2e5 = 6e6\) 。
程式碼:
#include <bits/stdc++.h>
#define seq(q, w, e) for (int q = w; q <= e; q++)
#define ll long long
using namespace std;
const int maxn = 6e6+10,maxx=2e5+10;
const int limt=1e9+10;
#define lson tree[p].ls
#define rson tree[p].rs
ll n,m;
ll tot,rt; //tot為點數,rt為根節點
ll posx[maxx]; //村莊位置
struct node{
ll ls,rs,sum; //sum為人口數
}tree[maxn];
void push_up(ll p){
tree[p].sum=tree[lson].sum+tree[rson].sum; //本質為求和線段樹
}
void insert(ll pos,ll &p,ll l,ll r,ll d){ //插入點
if(!p){ //開新的點
p=++tot;
lson=rson=tree[p].sum=0; //初始化
}
if(l==r){
tree[p].sum+=d; //維護人口
return;
}
ll mid=(l+r)>>1;
if(pos<=mid) insert(pos,lson,l,mid,d); //遞迴尋找
else insert(pos,rson,mid+1,r,d);
push_up(p);
}
ll query(ll l,ll r,ll p,ll pl,ll pr){
if(!p) return 0; //若不存在
if(l<=pl&&r>=pr) return tree[p].sum; //下為正常線段樹的求和函式
ll res=0,mid=(pl+pr)>>1;
if(l<=mid) res+=query(l,r,lson,pl,mid);
if(r>mid) res+=query(l,r,rson,mid+1,pr);
return res;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
seq(i,1,n){
cin>>posx[i];
}
seq(i,1,n){
ll op;
cin>>op;
insert(posx[i],rt,-limt,limt,op); //在值域中插入點
}
cin>>m;
seq(i,1,m){
int l,r;
cin>>l>>r;
cout<<query(l,r,rt,-limt,limt)<<"\n"; //區間查詢
}
return 0;
}