【bzoj】【1176】【mokia】【cdq分治】

Description

维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.

Input

第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小

接下来每行为一下三种输入之一(不包含引号):

"1 x y a"

"2 x1 y1 x2 y2"

"3"

输入1:你需要把(x,y)(第x行第y列)的格子权值增加a

输入2:你需要求出以左上角为(x1,y1),右下角为(x2,y2)的矩阵内所有格子的权值和,并输出

输入3:表示输入结束

Output

对于每个输入2,输出一行,即输入2的答案

Sample Input

0 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

保证答案不会超过int范围

题解:

          二维树状数组显然没法处理.

         考虑cdq分治,对于(l,r),处理(l,mid)中的修改操作对(mid+1,r)中的询问的影响.

         分析一下就是有若干点和若干矩形,然后需要计算每个矩形包含多少个点,

         这是个经典问题,按x排序,对y建树状数组即可.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2000010
#define M 200000
using namespace std;
int n,s,ans[M],num,tot,x1,y1,kind,x2,y2,t[N];
struct use{int x,y,v,kind,id,p;}q[M<<2],tr[M<<2];
int read(){
  int x(0);char ch=getchar();
  while (ch<'0'||ch>'9') ch=getchar();
  while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x;  
}
void get(){
  x1=read();y1=read();x2=read();y2=read();num++;
  q[++tot].p=num;q[tot].id=tot;q[tot].kind=1;q[tot].x=x1-1;q[tot].y=y1-1;q[tot].v=1;
  q[++tot].p=num;q[tot].id=tot;q[tot].kind=1;q[tot].x=x2;q[tot].y=y2;q[tot].v=1;
  q[++tot].p=num;q[tot].id=tot;q[tot].kind=1;q[tot].x=x1-1;q[tot].y=y2;q[tot].v=-1;
  q[++tot].p=num;q[tot].id=tot;q[tot].kind=1;q[tot].x=x2;q[tot].y=y1-1;q[tot].v=-1;
}
bool cmp(use a,use b){
  if (a.x==b.x){
    if (a.y==b.y) return a.id<b.id;
    else return a.y<b.y;
  }
  else return a.x<b.x;
}
int lowbit(int x){
  return x&(-x);
}
void add(int x,int v){
  for (int i=x;i<=n;i+=lowbit(i)) t[i]+=v;
}
int query(int x){
  int ans(0);
  for (int i=x;i;i-=lowbit(i)) ans+=t[i];
  return ans;
}
void solve(int l,int r){
  if (l==r) return;
  int mid=(l+r)>>1,l1=l,l2=mid+1;
  for (int i=l;i<=r;i++){
    if (q[i].id<=mid&&!q[i].kind) add(q[i].y,q[i].v);
    if (q[i].id>mid&&q[i].kind==1) ans[q[i].p]+=q[i].v*query(q[i].y);
  }
  for (int i=l;i<=r;i++)
    if (q[i].id<=mid&&!q[i].kind) add(q[i].y,-q[i].v);
  for (int i=l;i<=r;i++)
    if (q[i].id<=mid) tr[l1++]=q[i];
    else tr[l2++]=q[i];
  for (int i=l;i<=r;i++) q[i]=tr[i];
  solve(l,mid);solve(mid+1,r);
}
int main(){
   s=read();n=read();
   while (1){
     kind=read();
     if (kind==3) break;
     if (kind==1){
       q[++tot].x=read();q[tot].y=read();
       q[tot].v=read();q[tot].id=tot;
     }
     else get();
   }
   sort(q+1,q+tot+1,cmp);
   solve(1,tot);
   for (int i=1;i<=num;i++) printf("%d\n",ans[i]);
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值