水饺基情

1003 水饺基情

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)

Total Submission(s) : 43   Accepted Submission(s) : 4

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

在看完植物大战僵尸后,雄哥强烈要求zzy在203留宿,地点就在雄哥的睡袋上。是不是很基情??长夜漫漫无心睡眠,雄哥拿出了积攒已久的一盒水饺,(因为饿了= =)。半夜三更,四下无人,zzy和雄哥决定把水饺吃掉,但是!他们玩了一个十分基情的游戏。雄哥拿来了一张T*T的棋盘,决定把水饺铺到棋盘格子上。由于有两种味道的水饺,韭菜味的和白菜味的。韭菜味的用A表示,白菜味的用B表示。 将两种水饺以梅花分布形式铺满棋盘,例如:5*5的棋盘铺好后如下:
韭菜味 白菜味 韭菜味 白菜味 韭菜味
白菜味 韭菜味 白菜味 韭菜味 白菜味
韭菜味 白菜味 韭菜味 白菜味 韭菜味
白菜味 韭菜味 白菜味 韭菜味 白菜味
韭菜味 白菜味 韭菜味 白菜味 韭菜味
好了他们开始玩游戏了。约定两种操作
R a b c d:询问(a,b)->(c,d)范围内有多少个韭菜味和白菜味的水饺。
X a b: 代表将(a,b)点的水饺更新为X,X只有两种取值A或B。
好了,现在他们想知道多次更新后的棋盘在(a,b)->(c,d)的范围内有多少韭菜味的水饺和白菜味的水饺。

Input

输入包含多次操作,其中第一行是一个整数 T(1 ≤ T ≤ 1,000, 000),表示操作的次数,也是棋盘的宽度。
接下来是T行,分别对应Ti操作,格式有2种:
1.A或B开头,后跟2个整数x和y(1 ≤ x,y ≤ 1024),表示对(x,y)处的水饺进行更新
2.R 后面跟4个整数x1,y1,x2和y2(1 ≤ x1≤x2 ≤ 1024, 1 ≤ y1≤y2 ≤ 1024), 询问(x1,y1)->( x2,y2)范围内有韭菜味和白菜味的水饺的个数。

Output

针对每个询问操作,输出一行,有两个整数 回答(x1,y1)->( x2,y2)范围内有多少韭菜味和白菜味的水饺。

Sample Input

8

R 1 1 5 5

A 5 5

R 1 1 5 5

R 1 1 4 5

A 1 4

A 2 4

A 3 4

R 1 1 5 5

Sample Output

13 12

13 12

10 10

15 10

 

    比赛的时候目测是经典的二维线段树,然后开始纠结二维线段树怎么写,纠结了超过半小时后断然放弃(菜鸟的悲剧啊…)

赛后和大家讨论之后,发现其实只需稍稍转化下就可以用二维树状数组过掉的,可是那个时候我只会写一维的树状数组,压根儿不知二维所谓何物…

第二天上午起床之后果断开始学习二维树状数组,发现其实也不外如是。

    如果用“点”这个几何概念来形容一维的话,那么二维树状数组更接近“面”的概念。参见下图做一些简单的说明:

     现在我们想要知道(x1,y1)到(x2,y2)的这个子矩形的面积(或者认为他的每个点具有一定权值,这时可认为是求落在这个子矩形内的所有的点的权值和)。借助二维树状数组来解决是再方便不过的了。

     因为二维树状数组的getsum(x,y)是(x,y)点到原点的“面积和”,那么要求上图中子矩形的面积,其实就是(x2,y2)到原点的面积减去(x2,y1)、(x1,y2)分别到原点的面积,再加上(x1,y1)到原点的面积(因为这一部分被减了2次)。相信大家对这个处理肯定不陌生吧? 这不是我们初中数学的几何体嘛!

    好了,有了这些知识,那么应用二维树状数组就轻松啦!

 

   针对这个题目,如果我们将韭菜味饺子(A)赋值为1,将白菜味饺子(B)赋值为0,那么对子矩形面积求和之后,得到的返回值即为韭菜味饺子(A)的个数,白菜味饺子(B)就是子矩形的“面积”减去韭菜味饺子(A)的数值嘛! 是不是还是蛮巧妙的呢?

 

    下面给出二维树状数组的模板:

#define MAXN 1026
#define lowbit(x) x&(-x)
int T, c[MAXN][MAXN];

void add(int x, int y, int val)
{
    int i, j;
    for (i = x; i <= MAXN; i += lowbit(i))
        for (j = y; j <= MAXN; j+= lowbit(j))
            c[i][j] += val;
}

int getsum(int x, int y)
{
    int sum = 0, i, j;
    for (i = x; i > 0; i -= lowbit(i))
        for (j = y; j > 0; j -= lowbit(j))
            sum += c[i][j];
    return sum;
}

 

   不过针对这题,在初始化树状数组以及更新的时候还是做了一些简单的处理的:

    int i, j, t, a, b, cc, d;
    long long cnta, cntb;    //求和的时候可能会因为数据太大溢出,这是保险的措施
    char str[3];
    while(~scanf("%d",&t)){
           T= t;
           memset(c,0,sizeof(c));    //同一维一样,需要初始化时清零
           memset(matrix,0,sizeof(matrix));
           if(T>1024) T=1024;

           for(i=1; i<=T; ++i){
                  for(j=1; j<=T; ++j){
                         if((i%2 && j%2) || (i%2==0 && j%2==0)) {
                             update(i,j,1);
                             matrix[i][j] = 1;   //建立了一个matrix的数组来跟踪整个棋盘饺子数目的变化
                         }
                  }
           }

           for(i=0; i<t; ++i){
                  scanf("%s",str);
                  if(str[0]=='R'){
                          scanf("%d %d %d %d",&a,&b,&cc,&d);
                          cnta = getsum(cc,d);
                          if(b>1)  cnta-=getsum(cc,b-1);
                          if(a>1)  cnta-=getsum(a-1,d);
                          if(a>1 && b>1)  cnta+=getsum(a-1,b-1);
                          cntb = (cc-a+1)*(d-b+1)-cnta;
                          printf("%I64d %I64d\n",cnta,cntb);
                  }
                  else{
                         scanf("%d %d",&a,&b);
                         if(str[0]=='A' && matrix[a][b]==0){
                                  update(a,b,1);
                                  matrix[a][b] = 1;   //这里的matrix数值一定要跟着改变
                         }
                        else if(str[0]=='B' && matrix[a][b]==1){
                                  update(a,b,-1);
                                  matrix[a][b] = 0;
                        }
                  }
           }
    }

 

其实是很简单的一个题目,可惜自己的算法知识太少,当时根本不会二维的,就没能做出来…… 

 

 

posted on 2012-07-30 12:54  Yuna_  阅读(77)  评论(0)    收藏  举报