C93 二维树状数组 P4054 [JSOI2009] 计数问题

视频链接:C93 二维树状数组 P4054 [JSOI2009] 计数问题_哔哩哔哩_bilibili

 

 

Luogu P4054 [JSOI2009] 计数问题

//100个二维树状数组 点修+区查 O(n*n*logn*logn+q*logn*logn)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define lowb(x) x&-x
int n,m;
int a[301][301];      //格子的权值
int s[301][301][101]; //各权值在矩阵中出现的次数

void change(int x,int y,int c,int v){ //向后修
  for(int i=x;i<=n;i+=lowb(i))
    for(int j=y;j<=m;j+=lowb(j))
      s[i][j][c]+=v;
}
int query(int x,int y,int c){ //向前查
  int t=0;
  for(int i=x;i;i-=lowb(i))
    for(int j=y;j;j-=lowb(j))
      t+=s[i][j][c];
  return t;
}
int main(){
  int x1,y1,x2,y2,c,Q,op,ans;  
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j){
      scanf("%d",&c);
      a[i][j]=c;
      change(i,j,c,1);
    }
  scanf("%d",&Q);  
  while(Q--){
    scanf("%d",&op);
    if(op == 1){ //修改: 先减后加
      scanf("%d%d%d",&x1,&y1,&c);
      change(x1,y1,a[x1][y1],-1);
      a[x1][y1]=c;
      change(x1,y1,c,1);
    }
    else{ //查询: 二维区间和
      scanf("%d%d%d%d%d",&x1,&x2,&y1,&y2,&c);
      ans=query(x2,y2,c)-query(x1-1,y2,c)
         -query(x2,y1-1,c)+query(x1-1,y1-1,c);
      printf("%d\n",ans);
    }
  }
}

 

//100个二维树状数组 点修+区查 O(n*n*logn*logn+q*logn*logn)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define lowb(x) x&-x
int n,m;
int a[301][301];   //格子的权值

struct T{
  int s[301][301]; //各权值在矩阵中出现的次数
  void change(int x,int y,int k){ //向后修
    for(int i=x;i<=n;i+=lowb(i))
      for(int j=y;j<=m;j+=lowb(j))
        s[i][j]+=k;
  }
  int query(int x,int y){ //向前查
    int t=0;
    for(int i=x;i;i-=lowb(i))
      for(int j=y;j;j-=lowb(j))
        t+=s[i][j];
    return t;
  }  
}c[101];
void add(int x,int y,int v,int k){ //点加
  c[v].change(x,y,k);
}
int sum(int x1,int y1,int x2,int y2,int v){ //区间和
  return c[v].query(x2,y2)-c[v].query(x1-1,y2)
        -c[v].query(x2,y1-1)+c[v].query(x1-1,y1-1);
}
int main(){
  int x1,y1,x2,y2,v,Q,op,ans;  
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j){
      scanf("%d",&v);
      a[i][j]=v;
      add(i,j,v,1);
    }
  scanf("%d",&Q);  
  while(Q--){
    scanf("%d",&op);
    if(op == 1){ //修改: 先减后加
      scanf("%d%d%d",&x1,&y1,&v);
      add(x1,y1,a[x1][y1],-1);
      a[x1][y1]=v;
      add(x1,y1,v,1);
    }
    else{ //查询: 二维区间和
      scanf("%d%d%d%d%d",&x1,&x2,&y1,&y2,&v);
      printf("%d\n",sum(x1,y1,x2,y2,v));
    }
  }
}

 

posted @ 2024-01-15 16:25  董晓  阅读(118)  评论(0编辑  收藏  举报