zoukankan      html  css  js  c++  java
  • 【二维树状数组】See you~

    https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F

    【题意】

    给定一个矩阵,每个格子的初始值为1。现在可以对矩阵有四种操作:

    A x y n1 :给格点(x,y)的值加n1

    D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0

    M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个

    S x1 y1 x2 y2 查询子矩阵的和

    【思路】

    当然是二维树状数组

    但是一定要注意:lowbit(0)是死循环,一定不能是0。所以初始化格点为1的时候要从1开始,以及对于输入的坐标,我们要加1处理。

    【Accepted】

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<string>
      5 #include<algorithm>
      6 #include<cmath>
      7 
      8 using namespace std;
      9 typedef long long ll;
     10 int n;
     11 const int maxn=1e3+5;
     12 int bit[maxn][maxn];
     13 
     14 int lowbit(int x)
     15 {
     16     return (-x)&x;
     17 }
     18 
     19 void add(int x,int y,int val)
     20 {
     21     while(x<maxn)
     22     {
     23         int temp=y;
     24         while(temp<maxn)
     25         {
     26             bit[x][temp]+=val;
     27             temp+=lowbit(temp);
     28         }
     29         x+=lowbit(x);
     30     }
     31 }
     32 
     33 int sum(int x,int y)
     34 {
     35     int ans=0;
     36     while(x>0)
     37     {
     38         int temp=y;
     39         while(temp>0)
     40         {
     41             ans+=bit[x][temp];
     42             temp-=lowbit(temp);
     43         }
     44         x-=lowbit(x);
     45      } 
     46     return ans;
     47 }
     48 
     49 int solve(int x1,int y1,int x2,int y2)
     50 {
     51     return sum(x2,y2)-sum(x1-1,y2)-sum(x2,y1-1)+sum(x1-1,y1-1);
     52 }
     53 
     54 char op[5];
     55 int main()
     56 {
     57     int T;
     58     scanf("%d",&T);
     59     int cas=0;
     60     while(T--)
     61     {
     62         printf("Case %d:
    ",++cas);
     63         memset(bit,0,sizeof(bit));
     64         for(int i=1;i<maxn;i++)
     65         {
     66             for(int k=1;k<maxn;k++)
     67             {
     68                 add(i,k,1);
     69             }
     70         }
     71         scanf("%d",&n);
     72         for(int i=0;i<n;i++)
     73         {
     74         //    getchar();
     75             scanf("%s",op);
     76             if(op[0]=='S')
     77             {
     78                 int x1,y1,x2,y2;
     79                 scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
     80                 x1++;y1++;x2++;y2++;
     81                 if(x1>x2)
     82                 {
     83                     swap(x1,x2);
     84                 }
     85                 if(y1>y2)
     86                 {
     87                     swap(y1,y2);
     88                 }
     89                 printf("%d
    ",solve(x1,y1,x2,y2));
     90             }
     91             if(op[0]=='A')
     92             {
     93                 int x,y,n1;
     94                 scanf("%d%d%d",&x,&y,&n1);
     95                 x++;y++;
     96                 add(x,y,n1);
     97             }
     98             if(op[0]=='D')
     99             {
    100                 int x,y,n1;
    101                 scanf("%d%d%d",&x,&y,&n1);
    102                 x++;y++;
    103                 if(solve(x,y,x,y)<n1)
    104                 {
    105                     n1=solve(x,y,x,y);
    106                 }
    107                 add(x,y,-n1);
    108             }
    109             if(op[0]=='M')
    110             {
    111                 int x1,y1,x2,y2,n1;
    112                 scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&n1);
    113                 x1++;y1++;x2++;y2++;
    114                 if(solve(x1,y1,x1,y1)<n1)
    115                 {
    116                     n1=solve(x1,y1,x1,y1);
    117                 }
    118                 add(x1,y1,-n1);
    119                 add(x2,y2,n1);
    120             }
    121         }    
    122     }
    123     return 0;    
    124 }
    二维树状数组

    【知识点】

    1. 树状数组是O(logn)的,是因为n的二进制里最多有logn个1

    2. 注意:树状数组的下标必须从1开始,,因为lowbit(0)=0,如果从0开始的话就会陷入死循环!!树状数组适用于所有满足结合律的运算(加法,乘法,异或等)

    3. 所有树状数组能完成的操作线段树都能够完成,但是线段树的代码复杂,时间复杂度也比较高,查询、修改需要递归完成,而,树状数组的操作不仅代码简洁,便于理解,而且一切都是递推完成的,所以能用树状数组解决的问题尽量不要用线段树来写。

    4. 树状数组可以查找逆序对,对于LIS问题可以查找方案数。

  • 相关阅读:
    iOS开发基础知识--碎片7
    python---ORM之SQLAlchemy(3)外键与relationship的关系
    python---ORM之SQLAlchemy(2)外键使用
    python---ORM之SQLAlchemy(1)
    python---自定义字段验证
    mysql -- 慢日志使用
    mysql -- 索引补充
    mysql -- 动态获取结果集(重点)
    mysql -- 逻辑语句
    mysql -- 事务
  • 原文地址:https://www.cnblogs.com/itcsl/p/7123931.html
Copyright © 2011-2022 走看看