Description
你有一个的棋盘,每个格子内有一个整数,初始时的时候全部为,现在需要维护两种操作:
命令 | 参数限制 | 内容 |
---|---|---|
,是正整数 | 将格子里的数字加上 | |
输出这个矩形内的数字和 | ||
无 | 终止程序 |
Input
输入文件第一行一个正整数。
接下来每行一个操作。
Output
对于每个操作,输出一个对应的答案。
Sample Input
4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
3
5
HINT
,操作数不超过个,内存限制。
对于的数据,操作中的不超过。
Source
思路
把和的坐标加上操作的时间构成三维偏序。
代码
#include <cstdio>
#include <algorithm>
const int maxn=800000;
const int maxm=500000;
const int maxk=200000;
int n;
struct tree_array
{
int c[maxn+10];
inline int lowbit(int x)
{
return x&(-x);
}
inline int add(int pos,int x)
{
if(!pos)
{
return 0;
}
while(pos<=n)
{
c[pos]+=x;
pos+=lowbit(pos);
}
return 0;
}
inline int sum(int pos)
{
int res=0;
while(pos)
{
res+=c[pos];
pos-=lowbit(pos);
}
return res;
}
};
struct data
{
int x,y,id,v;
bool operator <(const data &other) const
{
return x<other.x;
}
};
int ans[maxm+10],m;
tree_array t;
data d[maxn+10];
int make_data(int a,int b,int c,int e)
{
++m;
d[m].x=a;
d[m].y=b;
d[m].id=c;
d[m].v=e;
return 0;
}
int solve(int l,int r)
{
if(l==r)
{
return 0;
}
int mid=(l+r)>>1;
solve(l,mid);
solve(mid+1,r);
std::sort(d+l,d+mid+1);
std::sort(d+mid+1,d+r+1);
int j=l;
for(register int i=mid+1; i<=r; ++i)
{
while((j<=mid)&&(d[j].x<=d[i].x))
{
t.add(d[j].y,d[j].v);
++j;
}
if(d[i].id)
{
ans[abs(d[i].id)]+=((d[i].id>0)?1:-1)*t.sum(d[i].y);
}
}
for(register int i=l; i<j; ++i)
{
t.add(d[i].y,-d[i].v);
}
return 0;
}
int tot,opt,a,b,c,e;
int main()
{
scanf("%d",&n);
while(1)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d%d%d",&a,&b,&c);
make_data(a,b,0,c);
}
else if(opt==2)
{
++tot;
scanf("%d%d%d%d",&a,&c,&b,&e);
make_data(std::min(a,b)-1,std::min(c,e)-1,tot,0);
make_data(std::min(a,b)-1,std::max(c,e),-tot,0);
make_data(std::max(a,b),std::min(c,e)-1,-tot,0);
make_data(std::max(a,b),std::max(c,e),tot,0);
}
else
{
break;
}
}
solve(1,m);
for(register int i=1; i<=tot; ++i)
{
printf("%d\n",ans[i]);
}
return 0;
}