pku2155 Matrix

这题的要求和树状数组的使用方法恰好相反,改变的是一个区间,查询的反而是一个点。我们先看一维的情况。

首先定义

Up(a)={a1=a,a2=a1+lowbit(a1),a3=a2+lowbit(a2) ... }

Down(a)={a1=a,a2=a1-lowbit(a1),a3=a2-lowbit(a2) ... }

为了方便讨论,只说明初始化后的第一次“C a b”和“Q c”操作:

对于命令“C a b”,我们分别调用函数down(b,1)和down(a-1,-1),将下标属于集合Down(b)的C中的元素+1,下标属于集合Down(a-1)的C中的元素-1,联系到通常树状数组的求和为down(b)-down(a-1),这里只不过把取值操作转变为对值的修改;

然后分情况讨论函数up(c)如何对点进行查询,可以发现对于任意的a<=b,Up(a)与Down(b)的交集只有一个元素。

因此

当a<c<=b时,Up(c)与Down(a-1)无交集,与Down(b)有交集且交集内只有一个元素,由之前的修改可知该元素为1,故返回1;

当b<c时,Up(c)与Down(b)无交集,故返回0;

当c<=a时,Up(c)分别与Down(b)和Down(a-1)构成一个元素的交集,其元素分别为-1和1,抵消后返回0;

此时返回值就是点c处的值。

了解如何获得第一次修改后的询问结果后,只要将简单的返回值变更为对下标属于集合Up(c)的C中元素的累加值,就能得到多次修改后的询问结果,然后扩展至二维即可

 

 

/*

Source Code

Problem: 2155  User: zgmf_x20a 
Memory: 4160K  Time: 438MS 
Language: C++  Result: Accepted 

*/

#include 
< iostream >
#include 
< algorithm >
using   namespace  std;

#define  MAXN 1005
#define  clr(x) memset(x,0,sizeof(x))

int  c[MAXN][MAXN],n,query;

inline 
int  lowbit( int  x){
    
return  x & ( - x);
}

void  down( int  x, int  y, int  tt){
    
int  i = x,j = y;
    
while (i > 0 ){
        j
= y;
        
while (j > 0 ){
            c[i][j]
+= tt;
            j
-= lowbit(j);
        }
        i
-= lowbit(i);
    }
}

int  up( int  x, int  y){
    
int  i = x,j = y,res = 0 ;
    
while (i <= n){
        j
= y;
        
while (j <= n){
            res
+= c[i][j];
            j
+= lowbit(j);
        }
        i
+= lowbit(i);
    }
    
return  res;
}

int  main(){
    
int  T,x1,y1,x2,y2;
    
char  str[ 3 ];
    scanf(
" %d " , & T);
    
while (T -- ){
        clr(c);
        scanf(
" %d%d " , & n, & query);
        
while (query -- ){
            scanf(
" %s " ,str);
            
if (str[ 0 ] == ' C ' ){
                scanf(
" %d%d%d%d " , & x1, & y1, & x2, & y2);
                down(x2,y2,
1 );
                down(x1
- 1 ,y2, - 1 );
                down(x2,y1
- 1 , - 1 );
                down(x1
- 1 ,y1 - 1 , 1 );
            }
            
else {
                scanf(
" %d%d " , & x1, & y1);
                printf(
" %d\n " ,up(x1,y1) % 2 );
            }
        }
        printf(
" \n " );
    }
    
return   0 ;
}

 

 

另附二维线段树代码

 

/*

Source Code

Problem: 2155  User: zgmf_x20a 
Memory: 56440K  Time: 1922MS 
Language: C++  Result: Accepted
 
*/


#include 
< iostream >
using   namespace  std;

#define  MAXN 1001
#define  clr(x) memset(x,0,sizeof(x))

int  n,m;

struct  Node{
    
int  l,r,cnt;
};

class  SegTree{
    Node nod[
3 * MAXN];
public :
    
void  BuildTree( int  u, int  l, int  r){
        nod[u].l
= l;
        nod[u].r
= r;
        nod[u].cnt
= 0 ;
        
if (l == r)
            
return ;
        BuildTree(
2 * u,l,(l + r) / 2 );
        BuildTree(
2 * u + 1 ,(l + r) / 2 + 1 ,r);
    }
    
void  Insert( int  u, int  l, int  r){
        
if (l <= nod[u].l  &&  nod[u].r <= r){
            nod[u].cnt
++ ;
            
return ;
        }
        
if (l <= nod[ 2 * u].r)
            Insert(
2 * u,l,r);
        
if (r >= nod[ 2 * u + 1 ].l)
            Insert(
2 * u + 1 ,l,r);

    }
    
int  Query( int  u, int  l, int  r, int  sum){
        sum
+= nod[u].cnt;
        
if (l <= nod[u].l  &&  nod[u].r <= r)
            
return  sum;
        
int  res = 0 ;
        
if (l <= nod[ 2 * u].r)
            res
+= Query( 2 * u,l,r,sum);
        
if (r >= nod[ 2 * u + 1 ].l)
            res
+= Query( 2 * u + 1 ,l,r,sum);
        
return  res;
    }
};

struct  _2DNode{
    SegTree tre;
    
// 二维线段树中每个区间被翻转的次数用一维线段树统计
     int  l,r;
};

class  _2DSegTree{
    _2DNode _2Dnod[
3 * MAXN];
public :
    
void  _2DBuildTree( int  u, int  xl, int  xr, int  yl, int  yr){
        _2Dnod[u].l
= xl;
        _2Dnod[u].r
= xr;
        _2Dnod[u].tre.BuildTree(
1 ,yl,yr);
        
if (xl == xr)
            
return ;
        _2DBuildTree(
2 * u,xl,(xl + xr) / 2 ,yl,yr);
        _2DBuildTree(
2 * u + 1 ,(xl + xr) / 2 + 1 ,xr,yl,yr);
    }
    
void  _2DInsert( int  u, int  xl, int  xr, int  yl, int  yr){
        
if (xl <= _2Dnod[u].l  &&  _2Dnod[u].r <= xr){
            _2Dnod[u].tre.Insert(
1 ,yl,yr);
            
return ;
        }
        
if (xl <= _2Dnod[ 2 * u].r)
            _2DInsert(
2 * u,xl,xr,yl,yr);
        
if (xr >= _2Dnod[ 2 * u + 1 ].l)
            _2DInsert(
2 * u + 1 ,xl,xr,yl,yr);
    }
    
int  _2DQuery( int  u, int  xl, int  xr, int  yl, int  yr, int  sum){
        sum
+= _2Dnod[u].tre.Query( 1 ,yl,yr, 0 );
        
if (xl <= _2Dnod[u].l  &&  _2Dnod[u].r <= xr)
            
return  sum;
        
int  res = 0 ;
        
if (xl <= _2Dnod[ 2 * u].r)
            res
+= _2DQuery( 2 * u,xl,xr,yl,yr,sum);
        
if (xr >= _2Dnod[ 2 * u + 1 ].l)
            res
+= _2DQuery( 2 * u + 1 ,xl,xr,yl,yr,sum);
        
return  res;
    }
};


_2DSegTree tr;


int  main(){
    
int  i,T,xl,xr,yl,yr;
    
char  str[ 3 ];
    scanf(
" %d " , & T);
    
while (T -- ){
        scanf(
" %d%d " , & n, & m);
        tr._2DBuildTree(
1 , 1 ,n, 1 ,n);
        
for (i = 0 ;i < m;i ++ ){
            scanf(
" %s " ,str);
            
if (str[ 0 ] == ' C ' ){
                scanf(
" %d%d%d%d " , & xl, & yl, & xr, & yr);
                tr._2DInsert(
1 ,xl,xr,yl,yr);
            }
            
else {
                scanf(
" %d%d " , & xl, & yl);
                printf(
" %d\n " ,tr._2DQuery( 1 ,xl,xl,yl,yl, 0 ) % 2 );
            }
        }
        printf(
" \n " );
    }
    
return   0 ;
}

转载于:https://www.cnblogs.com/zgmf_x20a/archive/2008/10/29/1322562.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值