题目概述
有 n×m 的网格,每个格子都有颜色 ci,j,1≤ci,j≤100 。给出 Q 个操作:1.询问一个子网格内某种颜色的个数。2.修改某格子的颜色。
解题报告
颜色数这么少,直接搞事情。线段树套线段树当然可以水过去啦,不过这种单点修改区间求和的问题我们当然会想到更简便的树状数组,所以这里介绍一下二维树状数组:
记录
这道题开 100 个二维树状数组就行了QwQ。
示例程序
#include<cstdio>
using namespace std;
const int maxn=300,maxm=300,maxc=100;
int n,m,te,a[maxn+5][maxm+5],tr[maxc+5][maxn+5][maxm+5];
#define Eoln(x) ((x)==10||(x)==13||(x)==EOF)
inline char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
inline int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst='+';
while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
return x=tot*f,Eoln(ch);
}
inline void writei(int x)
{
static int buf[10],len;len=0;do buf[len++]=x%10,x/=10; while (x);
for (int i=len-1;i>=0;i--) putchar(buf[i]+48);
}
inline void Update(int c,int x,int y,int tem)
{
for (int i=x;i<=n;i+=i&-i)
for (int j=y;j<=m;j+=j&-j)
tr[c][i][j]+=tem;
}
inline int Ask(int c,int x,int y)
{
int sum=0;
for (int i=x;i;i-=i&-i)
for (int j=y;j;j-=j&-j)
sum+=tr[c][i][j];
return sum;
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);readi(m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
readi(a[i][j]),Update(a[i][j],i,j,1);
for (readi(te);te;te--)
{
int td,A,B,C,D,c;readi(td);readi(A);readi(B);
if (td==1) readi(c),Update(a[A][B],A,B,-1),Update(a[A][B]=c,A,B,1); else
readi(C),readi(D),readi(c),writei(Ask(c,B,D)-Ask(c,B,C-1)-Ask(c,A-1,D)+Ask(c,A-1,C-1)),putchar('\n');
}
return 0;
}