BZOJ 2683 简单题

Description

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

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

Input

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

Output

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

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<=5000001<=N<=500000,操作数不超过200000200000个,内存限制20M20M
对于100100的数据,操作11中的AA不超过20002000

Source

思路

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

代码

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

转载于:https://www.cnblogs.com/Canopus-wym/p/10376242.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值