Description

你有一个N×N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:

命令 参数限制 内容
1 x y A 1<=x,y<=NA是正整数 将格子(x,y)里的数字加上A
2 x1 y1 x2 y2 1<=x1<=x2<=N1<=y1<=y2<=N 输出x1 y1 x2 y2这个矩形内的数字和
3 终止程序

Input

输入文件第一行一个正整数N
接下来每行一个操作。

Output

对于每个2操作,输出一个对应的答案。

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

1<=N<=500000,操作数不超过200000个,内存限制20M
对于100的数据,操作1中的A不超过2000

Source

思路

xy的坐标加上操作的时间T构成三维偏序。

代码

#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;
}