【题解】[JSOI2009]计数问题

Problem

( ext{Solution:})

开始有一种暴力的做法:对每一行维护 (100) 个树状数组对应 (100) 个颜色。查询枚举行来查询。

复杂度:(O(mcdot log ncdot q)) 过不去的样子。

考虑用二维树状数组,直接维护二维矩阵。修改与查询的复杂度都做到了 (O(log ncdot log m).)

于是最终复杂度可以做到 (O(qlog nlog m).)

注意树状数组实现上的细节:第二重循环要保证每次都是从 (y) 开始,所以要重新复制一个变量来做。而且两个维度的最大值也是不一样的,上界不同修改的时候要注意。

这题的树状数组显然没有 上帝造题的七分钟 那个树状数组难。这题算是入门版的二维树状数组。

维护矩阵同时维护一个颜色即可

#include<bits/stdc++.h>
using namespace std;
int tr[301][301][101],n,m,a[301][301],q;
inline int lowbit(int x){return x&(-x);}
void change(int x,int y,int c,int v){
	for(;x<=n;x+=lowbit(x))
		for(int i=y;i<=m;i+=lowbit(i))
			tr[x][i][c]+=v;
}
int query(int x,int y,int c){
	int res=0;
	for(;x;x-=lowbit(x))
		for(int i=y;i;i-=lowbit(i))
			res+=tr[x][i][c];
	return res;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j){
			scanf("%d",&a[i][j]);
			change(i,j,a[i][j],1);
		}
	scanf("%d",&q);
	for(;q;q--){
		int opt;
		scanf("%d",&opt);
		if(opt==1){
			int x,y,c;
			scanf("%d%d%d",&x,&y,&c);
			change(x,y,a[x][y],-1);
			a[x][y]=c;
			change(x,y,a[x][y],1);
		}
		else{
			int ax,bx,ay,by,c;
			scanf("%d%d%d%d%d",&ax,&bx,&ay,&by,&c);
			int ans=query(bx,by,c)-query(ax-1,by,c)-query(bx,ay-1,c)+query(ax-1,ay-1,c);
			printf("%d
",ans);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/h-lka/p/14944571.html