题意
给一个 (n imes n) 的矩阵,以螺旋线的形式给每个位置的预设值,有 (m) 个位置的值为本身的预设值,其余位置为 (0),然后 (p) 组询问,每组询问回答子矩阵中的总值为多少。
题解
有不少题解都是用离线树状数组的方法解决的,但是如果学习了主席树过后,可以发现主席树是解决这种二维偏序问题的利器。
首先对于 (m) 个有值得点,(O(1)) 地求出它得价值,不会得可以去学习一下螺旋矩阵
因为坐标在 (2cdot 10^6) 范围里,对于主席树来说有点大了,所以把 (y) 坐标离散化,这样主席树开 (mlog_2m) 个点就好。
然后把每个点以 (x) 坐标从小到大排序之后依次更改主席树,这颗主席树相当于维护了 (m) 个线段树,每个线段树统计已加入的点 (y) 坐标在区间 ([l,r]) 中的所有点的总价值是多少。
对于每个询问,看 ([x1,x2]) 这个区间里的信息是由哪两颗线段树的差值形成的,然后查询这两颗线段树在区间 ([y1,y2]) 中的差值总和,就是答案了,当然由于离散化,所以 (y1,y2) 一定要以离散化后的区间为准。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e5+10;
int n,m,p,root[MAXN];
int b[MAXN],cnt;
struct Point{
int x,y;
LL v;
void getv(){
int mid=(n+1)>>1;
int tx=x-mid,ty=y-mid;
LL c=max(abs(tx),abs(ty));
LL id=c*(c-1)*8/2;
if(ty==c&&-c<=tx&&tx<c) id+=c-tx;
else if(tx==-c&&-c<=ty&&ty<c) id+=c*2+c-ty;
else if(ty==-c&&-c<tx&&tx<=c) id+=2*c*2+c+tx;
else id+=3*c*2+c+ty;
LL temp=1ll*n*n-id;
v=0;
while(temp) v+=temp%10,temp/=10;
}
friend bool operator < (const Point& a,const Point& b){
return a.x<b.x;
}
}pt[MAXN];
struct HjtTree{
#define mid ((l+r)>>1)
LL sum[MAXN*40];
int ls[MAXN*40],rs[MAXN*40],tot;
void build(int& id,int l,int r){
id=++tot;sum[id]=0;
if(l==r) return;
build(ls[id],l,mid);
build(rs[id],mid+1,r);
}
void update(int pre,int& id,int l,int r,int pos,LL x){
id=++tot;sum[id]=sum[pre]+x;ls[id]=ls[pre];rs[id]=rs[pre];
if(l==r) return;
if(pos<=mid) update(ls[pre],ls[id],l,mid,pos,x);
else update(rs[pre],rs[id],mid+1,r,pos,x);
}
LL ask(int u,int v,int l,int r,int L,int R){
if(L<=l&&r<=R) return sum[v]-sum[u];
LL res=0;
if(L<=mid) res+=ask(ls[u],ls[v],l,mid,L,R);
if(R>mid) res+=ask(rs[u],rs[v],mid+1,r,L,R);
return res;
}
#undef mid
}tree;
void solve(){
scanf("%d%d%d",&n,&m,&p);
cnt=0;
for(int i=1;i<=m;i++){
scanf("%d%d",&pt[i].x,&pt[i].y);pt[i].getv();
b[++cnt]=pt[i].y;
}
sort(b+1,b+cnt+1);cnt=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<=m;i++) pt[i].y=lower_bound(b+1,b+cnt+1,pt[i].y)-b;
sort(pt+1,pt+m+1);
tree.tot=0;
tree.build(root[0],1,cnt);
for(int i=1;i<=m;i++) tree.update(root[i-1],root[i],1,cnt,pt[i].y,pt[i].v);
for(int i=1,x1,y1,x2,y2;i<=p;i++){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int u=lower_bound(pt+1,pt+m+1,(Point){x1,0,0})-pt-1;
int v=upper_bound(pt+1,pt+m+1,(Point){x2,0,0})-pt-1;
int l=lower_bound(b+1,b+cnt+1,y1)-b;
int r=upper_bound(b+1,b+cnt+1,y2)-b-1;
if(u>v||l>r) printf("0
");
else printf("%lld
",tree.ask(root[u],root[v],1,cnt,l,r));
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
#endif
int T;scanf("%d",&T);
while(T--) solve();
return 0;
}