先將詢問離線,從小到大掃描右端點並維護左端點的答案。讓每一個關鍵點在能覆蓋它的矩形中編號最大一個有貢獻,每次詢問就是查詢矩形對應的區間貢獻和。c++
每次右端點移動時,考慮新加入的矩形覆蓋的點集,將該點集有貢獻的位置修改成當前的右端點。這一過程能夠用 \(K-D\ Tree\) 來維護,暴力回收子樹內的標記,複雜度還是正確的,由於回收標記時以前已經有打標記的複雜度了。git
一共有 \(O(m\sqrt n)\) 次單點修改和 \(O(q)\) 次區間查詢,所以用分塊來維護,總複雜度爲 \(O\left(m\sqrt n+q\sqrt m\right)\)。ui
#include<bits/stdc++.h> #define maxn 1000010 using namespace std; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } int n,m,q,S,root,tot,type; int ans[maxn],bel[maxn],a[maxn],add[maxn]; vector<pair<int,int> > ve[maxn]; struct tree { int d[2],mx[2],mn[2],ls,rs,val,sum,tim,tag,vis; }t[maxn],dat[maxn]; bool cmp(const tree &a,const tree &b) { return a.d[type]<b.d[type]; } struct matrix { int u,d,l,r; }mt[maxn]; void update(int x,int v) { a[x]+=v,add[bel[x]]+=v; } int ask(int x) { int v=0; for(int i=x;i<=min(S*bel[x],m);++i) v+=a[i]; for(int i=bel[x]+1;i<=bel[m];++i) v+=add[i]; return v; } void pushup(int x) { int ls=t[x].ls,rs=t[x].rs; for(int i=0;i<=1;++i) { t[x].mx[i]=t[x].mn[i]=t[x].d[i]; if(ls) { t[x].mx[i]=max(t[x].mx[i],t[ls].mx[i]); t[x].mn[i]=min(t[x].mn[i],t[ls].mn[i]); } if(rs) { t[x].mx[i]=max(t[x].mx[i],t[rs].mx[i]); t[x].mn[i]=min(t[x].mn[i],t[rs].mn[i]); } } t[x].sum=t[ls].sum+t[rs].sum+t[x].val; } void del(int x) { if(t[x].tag) update(t[x].tag,-t[x].sum),t[x].tag=t[x].tim=0; if(t[x].tim) update(t[x].tim,-t[x].val),t[x].tim=0; } void pushdown(int x) { if(!t[x].tag) return; int ls=t[x].ls,rs=t[x].rs; del(ls),del(rs),t[ls].tag=t[ls].tim=t[rs].tag=t[rs].tim=t[x].tag; t[ls].vis=t[rs].vis=1,t[x].tag=0; } void build(int l,int r,int k,int &x) { x=++tot,type=k; int mid=(l+r)>>1; nth_element(dat+l+1,dat+mid+1,dat+r+1,cmp),t[x]=dat[mid]; if(l<mid) build(l,mid-1,k^1,t[x].ls); if(r>mid) build(mid+1,r,k^1,t[x].rs); pushup(x); } bool check(int x,int p) { return mt[p].u<=t[x].d[0]&&mt[p].d>=t[x].d[0]&&mt[p].l<=t[x].d[1]&&mt[p].r>=t[x].d[1]; } bool in(int x,int p) { return mt[p].u<=t[x].mn[0]&&mt[p].d>=t[x].mx[0]&&mt[p].l<=t[x].mn[1]&&mt[p].r>=t[x].mx[1]; } bool out(int x,int p) { return mt[p].u>t[x].mx[0]||mt[p].d<t[x].mn[0]||mt[p].l>t[x].mx[1]||mt[p].r<t[x].mn[1]; } void clear(int x) { if(!x||!t[x].vis) return; del(x),clear(t[x].ls),clear(t[x].rs),t[x].vis=0; } void modify(int x,int p) { if(!x||out(x,p)) return; if(in(x,p)) { clear(x),update(t[x].tag=t[x].tim=p,t[x].sum),t[x].vis=1; return; } if(check(x,p)) update(t[x].tim,-t[x].val),update(t[x].tim=p,t[x].val); pushdown(x),t[x].vis=1,modify(t[x].ls,p),modify(t[x].rs,p); } int main() { read(n); for(int i=1;i<=n;++i) read(dat[i].d[1]),read(dat[i].val),dat[i].d[0]=i; read(m),S=sqrt(m); for(int i=1;i<=m;++i) bel[i]=(i-1)/S+1,read(mt[i].u),read(mt[i].d),read(mt[i].l),read(mt[i].r); read(q); for(int i=1,l,r;i<=q;++i) read(l),read(r),ve[r].push_back(make_pair(l,i)); build(1,n,0,root); for(int i=1;i<=m;++i) { modify(root,i); for(int j=0;j<ve[i].size();++j) ans[ve[i][j].second]=ask(ve[i][j].first); } for(int i=1;i<=q;++i) printf("%d\n",ans[i]); return 0; }