题目链接:https://nanti.jisuanke.com/t/41298
题目大意:给出一个n*n的螺旋递减的矩阵,其中只有m个元素是有效的。对于q此询问,找出询问矩阵的有效元素数位之和!!
思路:首先要有一个映射函数,将螺旋递减矩阵映射成真实值,很容易,洛谷有一个类似的题,把当时的代码改一改就好了:https://www.luogu.org/problem/P2239。然后就是求询问区间了。当时想的二维前缀和+容斥,但是一直没有思路,存不下!后来才想到,将询问也离线一下就好了。x坐标排序,然后依次放入,就可以直接求前缀和了,由于保证输入的是右下和左上,因此就可以确定容斥的区间了。注意一个坑点!是数位之和,不是元素值之和。。当时一直求的元素和,一直WA,最后都没搞出来。。好惨啊QAQ,自闭中,比较沮丧
ACCode:
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=1e5+10;
const int MAXM=1e6+10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)
struct SegTree{
struct Node{
int l,r,len;
ll Sum;
};
Node Tree[MAXM<<2];
void PushUp(int rt){
Tree[rt].Sum=Tree[rt<<1].Sum+Tree[rt<<1|1].Sum;
}
void Build(int l,int r,int rt){
Tree[rt].l=l;Tree[rt].r=r;
Tree[rt].Sum=0;
if(l==r) return ;
int mid=(l+r)>>1;
Build(l,mid,rt<<1);Build(mid+1,r,rt<<1|1);
}
void Update(int pos,ll val,int rt){
if(pos==0) return ;
if(Tree[rt].l==Tree[rt].r){
Tree[rt].Sum+=val;
return ;
}
if(pos<=Tree[rt<<1].r) Update(pos,val,rt<<1);
else Update(pos,val,rt<<1|1);
PushUp(rt);
}
ll Query(int ql,int qr,int rt){
if(ql>qr) return 0;
if(ql<=Tree[rt].l&&Tree[rt].r<=qr) return Tree[rt].Sum;
if(qr<=Tree[rt<<1].r) return Query(ql,qr,rt<<1);
else if(ql>=Tree[rt<<1|1].l) return Query(ql,qr,rt<<1|1);
else return 1ll*Query(ql,qr,rt<<1)+Query(ql,qr,rt<<1|1);
}
void Show(int rt){
printf("l=%d r=%d Sum=%lld\n",Tree[rt].l,Tree[rt].r,Tree[rt].Sum);
if(Tree[rt].l==Tree[rt].r) return ;
Show(rt<<1);Show(rt<<1|1);
}
};
struct Point{
int i,j,val,opt;
friend int operator < (Point a,Point b){
if(a.i!=b.i) return a.i<b.i;
if(a.j!=b.j) return a.j<b.j;
return a.opt<b.opt;
}
};
SegTree Seg;
Point Dots[MAXN],Suf[MAXM];
PII Ask[MAXN][2];
ll Ans[MAXM];
map<PII,int> MP;
ll GetVal(int n,int i,int j){
ll ans;
ll mi=min(i,min(j,min(n-i+1,n-j+1)));
if(i<=j) ans=1ll*mi*(1ll*4*(n-1)-4*mi)+1ll*10*mi-4*n-3+i+j;
else ans=1ll*mi*(4*n-4*mi)+1ll*2*mi+1-i-j;//模拟过程
return ans;
}
ll Work(int n,int i,int j){
ll x=GetVal(n,n+1-i,n+1-j),ans=0;
while(x){
ans+=x%10;
x/=10;
}return ans;
}
int main(){
int T;scanf("%d",&T);
while(T--){
MP.clear();
int n,m,q;scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;++i){
int x,y;scanf("%d%d",&x,&y);
Dots[i].i=x;Dots[i].j=y;Dots[i].val=Work(n,x,y);
}
for(int i=1;i<=q;++i){
int x1,x2,y1,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
Ask[i][0]=make_pair(x1,y1);Ask[i][1]=make_pair(x2,y2);
}
Seg.Build(1,MAXM,1);
int sum=m+4*q;
for(int i=1;i<=m;++i){//共m个有效点
int x=Dots[i].i,y=Dots[i].j;
Suf[i].i=x;Suf[i].j=y;Suf[i].val=Dots[i].val;Suf[i].opt=1;
}
for(int i=1;i<=q;++i){//共q个询问点
Suf[i+m].i=Ask[i][0].first-1;Suf[i+m].j=Ask[i][0].second-1;Suf[i+m].opt=2;
Suf[i+m+q].i=Ask[i][0].first-1;Suf[i+m+q].j=Ask[i][1].second;Suf[i+m+q].opt=2;
Suf[i+m+2*q].i=Ask[i][1].first;Suf[i+m+2*q].j=Ask[i][0].second-1;Suf[i+m+2*q].opt=2;
Suf[i+m+3*q].i=Ask[i][1].first;Suf[i+m+3*q].j=Ask[i][1].second;Suf[i+m+3*q].opt=2;
}sort(Suf+1,Suf+sum+1);//将询问点排序
// for(int i=1;i<=sum;++i) printf("i=%d j=%d val=%lld opt=%d\n",Suf[i].i,Suf[i].j,Suf[i].val,Suf[i].opt);
for(int i=1;i<=sum;++i){
int x=Suf[i].i,y=Suf[i].j,val=Suf[i].val,opt=Suf[i].opt;
if(opt==1){//是一个宫殿
Seg.Update(y,val,1);
}
else{//是一个起点||其他询问点||终点,刷新答案后不用换
Ans[i]=Seg.Query(1,y,1);
MP[make_pair(x,y)]=i;
// printf("x=%d y=%d Ans=%lld\n",x,y,Ans[MP[make_pair(x,y)]]);
}
}
//Ans=[x2][y2]-[x2][y1-1]-[x1-1][y2]+[x1-1][y1-1];
for(int i=1;i<=q;++i){
PII str=Ask[i][0],ed=Ask[i][1];
ll ans=Ans[MP[make_pair(ed.first,ed.second)]]-Ans[MP[make_pair(ed.first,str.second-1)]]-Ans[MP[make_pair(str.first-1,ed.second)]]+Ans[MP[make_pair(str.first-1,str.second-1)]];
// printf("%lld - %lld - %lld + %lld = %lld\n",Ans[MP[make_pair(ed.first,ed.second)]],Ans[MP[make_pair(ed.first,str.second-1)]],Ans[MP[make_pair(str.first-1,ed.second)]],Ans[MP[make_pair(str.first-1,str.second-1)]],ans);
printf("%lld\n",ans);
}
}
}
/*
2
3 4 4
1 1
2 2
3 3
2 3
1 1 1 1
2 2 3 3
1 1 3 3
1 2 2 3
5 5 4
1 1
2 3
3 3
4 4
5 2
1 1 3 3
2 2 3 3
4 2 4 4
3 1 5 5
*/