【JSOI2009】计数问题

题目链接

开颜色种类个二维树状数组,维护前缀和,单点修改、子矩阵查询。

注意读入的顺序,是$x_1; x_2; y_1; y_2$而不是$x_1; y_1; x_2; y_2$。

代码(100分):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define IL inline
#define RG register
#define _1 first
#define _2 second
using namespace std;
const int N=300;
const int M=100;

    int n,m,q,a[N+3][N+3];
    int s[M+3][N+3][N+3];
    
IL int lowbit(int x){
    return x&(-x);
}
    
IL void mdfm(int k,int p,int q,int x){
    for(;q<=m;q+=lowbit(q))
        s[k][p][q]+=x;
}

IL void mdfn(int k,int p,int q,int x){
    for(;p<=n;p+=lowbit(p))
        mdfm(k,p,q,x);
}

IL int qrym(int k,int p,int q){
    int ret=0;
    for(;q;q-=lowbit(q))
        ret+=s[k][p][q];
    return ret;
}

IL int qryn(int k,int p,int q){
    int ret=0;
    for(;p;p-=lowbit(p))
        ret+=qrym(k,p,q);
    return ret;
}

IL int qry(int x1,int y1,int x2,int y2,int c){
    return qryn(c,x2,y2)-qryn(c,x1-1,y2)-qryn(c,x2,y1-1)+qryn(c,x1-1,y1-1);
}

IL void dat_init(){
    memset(s,0,sizeof s);
}

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]);
            
    dat_init();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            mdfn(a[i][j],i,j,1);
            
    scanf("%d",&q);
    while(q--){
        int opt;
        scanf("%d",&opt);
        if(opt==1){
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            
            mdfn(a[x][y],x,y,-1);
            mdfn(c,x,y,1);
            a[x][y]=c;
            
        }
        else {
            int x1,x2,y1,y2,c;
            scanf("%d%d%d%d%d",&x1,&x2,&y1,&y2,&c);
            
            printf("%d
",qry(x1,y1,x2,y2,c));
            
        }
        
    }

    return 0;

}
View Code
原文地址:https://www.cnblogs.com/Hansue/p/12954871.html