题目:
题解:
Emmm,这不是那道【简单题】吗,一眼二维树状数组
这道题目不强制在线啦,那我们可以用cdq分治
把每个询问拆成二维前缀和的形式,用乘1/-1的方式确定正负,至于方格里每个数的值嘛,我们就在权值树状数组中加多少就好啦
要对每个询问求符合如下条件的修改操作的贡献:
1.时间在它之前
2.x坐标小于等于它
3.y坐标小于等于它
三维偏序!
按照时间分治,x坐标排序,y坐标树状数组
“拆询问”和“按照时间排序”的思路都是CDQ分治的题目中非常常用的,有利于找到题目中的三维偏序关系
然后调了好久发现是把f赋给了jl。。。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N=500005;
struct hh{int x,y,id,z,f;}jl[800005],f[800005];
int n,c[N],ans[N],lj;bool flag[N];
void add(int loc,int val)
{
for (int i=loc;i<=n;i+=i&(-i))
c[i]+=val;
}
int qurry(int loc)
{
int ans=0;
for (int i=loc;i>=1;i-=i&(-i)) ans+=c[i];
return ans;
}
void cdq(int l,int r)
{
if (l>=r) return;
int mid=(l+r)>>1;
cdq(l,mid);cdq(mid+1,r);
int t1=l,t2=mid+1;
for (int i=l;i<=r;i++)
{
if ((t1<=mid && f[t1].x<=f[t2].x) || t2>r)
{
jl[i]=f[t1];
if (!flag[f[t1].id]) add(f[t1].y,f[t1].z);
t1++;
}
else
{
jl[i]=f[t2];
ans[f[t2].id]+=f[t2].f*qurry(f[t2].y);
t2++;
}
}
for (int i=l;i<=mid;i++)
if (!flag[f[i].id]) add(f[i].y,-f[i].z);
for (int i=l;i<=r;i++) f[i]=jl[i];
}
int main()
{
scanf("%d",&n);int T=0,id,gs=0;
while (scanf("%d",&id))
{
if (id==3) break;
++T;
if (id==1) f[++gs].id=T,scanf("%d%d%d",&f[gs].x,&f[gs].y,&f[gs].z),f[gs].f=0;
else if (id==2)
{
flag[T]=1;int x,y,a,b;
scanf("%d%d%d%d",&a,&b,&x,&y);
f[++gs].x=a-1; f[gs].y=b-1; f[gs].f=1; f[gs].id=T;
f[++gs].x=a-1; f[gs].y=y; f[gs].f=-1; f[gs].id=T;
f[++gs].x=x; f[gs].y=b-1; f[gs].f=-1; f[gs].id=T;
f[++gs].x=x; f[gs].y=y; f[gs].f=1; f[gs].id=T;
}
}
cdq(1,gs);
for (int i=1;i<=T;i++) if (flag[i]) printf("%d\n",ans[i]);
}