P1716 - 上帝造题的七分钟

From Riatre    Normal (OI)
总时限:50s    内存限制:128MB    代码长度限制:64KB

背景 Background

裸体就意味着身体。

描述 Description

“第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵。
第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作。
第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作。
第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围。
第五分钟,和雪说,要有耐心,于是便有了时间限制。
第六分钟,吃钢琴男说,要省点事,于是便有了保证运算过程中及最终结果均不超过32位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。”
——《上帝造裸题的七分钟》
所以这个神圣的任务就交给你了。

输入格式 InputFormat

输入数据的第一行为X n m,代表矩阵大小为n×m。
从输入数据的第二行开始到文件尾的每一行会出现以下两种操作:
    L a b c d delta —— 代表将(a,b),(c,d)为顶点的矩形区域内的所有数字加上delta。
    k a b c d     —— 代表求(a,b),(c,d)为顶点的矩形区域内所有数字的和。

请注意,k为小写。

输出格式 OutputFormat

针对每个k操作,在单独的一行输出答案。

样例输入 SampleInput [复制数据]

X 4 4
L 1 1 3 3 2
L 2 2 4 4 1
k 2 2 3 3

样例输出 SampleOutput [复制数据]

12

数据范围和注释 Hint

对于10%的数据,1 ≤ n ≤ 16, 1 ≤ m ≤ 16, 操作不超过200个.
对于60%的数据,1 ≤ n ≤ 512, 1 ≤ m ≤ 512.
对于100%的数据,1 ≤ n ≤ 2048, 1 ≤ m ≤ 2048, 1 ≤ delta ≤ 500,操作不超过200000个,保证运算过程中及最终结果均不超过32位带符号整数类型的表示范围。

来源 Source

by XLk

状态
Accepted
题号 P1716
类型(?) 高级数据结构
通过 99人
提交 392次
通过率 25%
 
  热烈庆祝AC200~~
  这道题被hja坑去写二维线段树,结果不是TLE就是MLE,正确的做法是二维树状数组区间修改与区间查询,在网上找得到详细解法。
大体思路为维护a[][]使得前缀和sum[x][y]=segma(num[i][j])=segma(a[i][j]*(x-i+1)*(y-j+1))=segma(a[i][j]*(x+1)*(y+1)-(i+j)*a[i][j])
=segma(a[i][j])*(x+1)*(y+1)+segma(i*j*a[i][j])-segma(j*a[i][j])*(x+1)-segma(i*a[i][j])*(y+1)
最后,可以用4个树状数组分别维护上式中segma中引用部分。
  下面贴上两种解法代码
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 2050
#define MAXT 5000000
typedef int tree_t[MAXN][MAXN];
tree_t tree1,tree2,tree3,tree4;
int lowbit(int x)
{
return x&(-x);
}
void add_val(tree_t tree,int x,int y,int v)
{
// cout<<"ADD"<<x<<" "<<y<<" "<<v<<endl;
int i,j;
for (i=x;i<MAXN;i+=lowbit(i))
{
for (j=y;j<MAXN;j+=lowbit(j))
{
tree[i][j]+=v;
}
}
}
int query_sum(tree_t tree,int x,int y)
{
int i,j;
int ret=;
for (i=x;i;i-=lowbit(i))
{
for (j=y;j;j-=lowbit(j))
{
ret+=tree[i][j];
}
}
return ret;
}
//sum(x,y)=segma(a[i][j]*(x-i+1)*(y-j+1))
// =segma(a[i][j]*(x+1)*(y+1)-(i+j)*a[i][j]);
// =segma(a[i][j])*(x+1)*(y+1)-segma((i+j)*a[i][j])
//
void add_matrix(int xl,int yl,int xr,int yr,int v)
{
add_val(tree1,xr+,yr+,v);
add_val(tree1,xl,yl,v);
add_val(tree1,xl,yr+,-v);
add_val(tree1,xr+,yl,-v);
add_val(tree2,xr+,yr+,v*(xr+)*(yr+));
add_val(tree2,xl,yl,v*(xl+)*(yl+));
add_val(tree2,xl,yr+,-v*(xl+)*(yr+));
add_val(tree2,xr+,yl,-v*(yl+)*(xr+)); add_val(tree3,xr+,yr+,v*(xr+));
add_val(tree3,xl,yl,v*(xl+));
add_val(tree3,xl,yr+,-v*(xl+));
add_val(tree3,xr+,yl,-v*(xr+)); add_val(tree4,xr+,yr+,v*(yr+));
add_val(tree4,xl,yl,v*(yl+));
add_val(tree4,xl,yr+,-v*(yr+));
add_val(tree4,xr+,yl,-v*(yl+)); }
int query_matrix(int x,int y)
{
if (!x || !y)return ;
int ret=;
int t;
ret+=query_sum(tree1,x,y)*(x+)*(y+);
ret-=(t=query_sum(tree3,x,y))*(y+);
ret-=query_sum(tree4,x,y)*(x+);
ret+=query_sum(tree2,x,y);
return ret;
}
int main()
{
freopen("input.txt","r",stdin);
int i,j,k;
int n,m;
int x,y,z;
char opt;
scanf("%c%d%d\n",&opt,&n,&m);
int a,b,c,d,e;
while (~scanf("%c",&opt))
{
if (opt=='L')
{
scanf("%d%d%d%d%d\n",&a,&b,&c,&d,&e);
add_matrix(a,b,c,d,e);
}else
{
scanf("%d%d%d%d\n",&a,&b,&c,&d);
printf("%d\n",query_matrix(a-,b-)+query_matrix(c,d)
-query_matrix(a-,d)-query_matrix(c,b-));
}
}
}

树状数组解法

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 2050
#define MAXT 2000000
#define midx ((tree[now].lx+tree[now].rx)>>1)
#define midy ((tree[now].ly+tree[now].ry)>>1)
#define tnly tree[now].ly
#define tnry tree[now].ry
#define tnlx tree[now].lx
#define tnrx tree[now].rx
#define tnlazy tree[now].lazy
#define area(t) ((tree[t].rx-tree[t].lx+1)*(tree[t].ry-tree[t].ly+1))
struct node
{
int ch[][];
int lx,rx,ly,ry;
int sum;
int lazy=;
}tree[MAXT];
int root=,topt=;
void new_node(int &now,int lx,int rx,int ly,int ry)
{
if (lx>rx ||ly>ry)return ;
now=++topt;
tnlx=lx;
tnrx=rx;
tnly=ly;
tnry=ry;
} void down(int now)
{
if (!tree[now].ch[][])
new_node(tree[now].ch[][],tnlx,midx,tnly,midy);
if (!tree[now].ch[][] && tnly<tnry)
new_node(tree[now].ch[][],tnlx,midx,midy+,tnry);
if (!tree[now].ch[][] && tnlx<tnrx)
new_node(tree[now].ch[][],midx+,tnrx,tnly,midy);
if (!tree[now].ch[][] && tnly<tnry && tnlx<tnrx)
new_node(tree[now].ch[][],midx+,tnrx,midy+,tnry);
if (tnlazy)
{
tree[tree[now].ch[][]].sum+=tnlazy*area(tree[now].ch[][]);
tree[tree[now].ch[][]].lazy+=tnlazy;
if (tnlx<tnrx)
{
tree[tree[now].ch[][]].sum+=tnlazy*area(tree[now].ch[][]);
tree[tree[now].ch[][]].lazy+=tnlazy;
}
if (tnly<tnry)
{
tree[tree[now].ch[][]].sum+=tnlazy*area(tree[now].ch[][]);
tree[tree[now].ch[][]].lazy+=tnlazy;
}
if (tnlx<tnrx && tnly<tnry)
{
tree[tree[now].ch[][]].sum+=tnlazy*area(tree[now].ch[][]);
tree[tree[now].ch[][]].lazy+=tnlazy;
}
tnlazy=;
}
}
void up(int now)
{
tree[now].sum=;
tree[now].sum+=tree[tree[now].ch[][]].sum;
tree[now].sum+=tree[tree[now].ch[][]].sum;
tree[now].sum+=tree[tree[now].ch[][]].sum;
tree[now].sum+=tree[tree[now].ch[][]].sum;
}
void add_val(int &now,int lx,int rx,int ly,int ry,int v)
{
if (tnlx==lx &&tnly==ly && tnrx==rx &&tnry==ry)
{
tree[now].sum+=v*(rx-lx+)*(ry-ly+);
tree[now].lazy+=v;
return ;
}
down(now);
if (rx<=midx && ry<=midy)
{
add_val(tree[now].ch[][],lx,rx,ly,ry,v);
up(now);
return ;
}
if (rx<=midx && ly> midy)
{
add_val(tree[now].ch[][],lx,rx,ly,ry,v);
up(now);
return ;
}
if (lx> midx && ry<=midy)
{
add_val(tree[now].ch[][],lx,rx,ly,ry,v);
up(now);
return ;
}
if (lx> midx && ly> midy)
{
add_val(tree[now].ch[][],lx,rx,ly,ry,v);
up(now);
return ;
}
if (rx<=midx)
{
add_val(tree[now].ch[][],lx,rx,ly,midy,v);
add_val(tree[now].ch[][],lx,rx,midy+,ry,v);
up(now);
return ;
}
if (lx> midx)
{
add_val(tree[now].ch[][],lx,rx,ly,midy,v);
add_val(tree[now].ch[][],lx,rx,midy+,ry,v);
up(now);
return ;
}
if (ry<=midy)
{
add_val(tree[now].ch[][],lx,midx,ly,ry,v);
add_val(tree[now].ch[][],midx+,rx,ly,ry,v);
up(now);
return ;
}
if (ly> midy)
{
add_val(tree[now].ch[][],lx,midx,ly,ry,v);
add_val(tree[now].ch[][],midx+,rx,ly,ry,v);
up(now);
return ;
}
add_val(tree[now].ch[][],lx,midx,ly,midy,v);
add_val(tree[now].ch[][],lx,midx,midy+,ry,v);
add_val(tree[now].ch[][],midx+,rx,ly,midy,v);
add_val(tree[now].ch[][],midx+,rx,midy+,ry,v);
up(now);
return ;
}
int query(int now,int lx,int rx,int ly,int ry)
{
if (tree[now].lx==lx && tree[now].rx==rx &&
tree[now].ly==ly && tree[now].ry==ry)
{
return tree[now].sum;
}
down(now);
int ans=;
if (rx<=midx && ry<=midy)
{
ans=query(tree[now].ch[][],lx,rx,ly,ry);
return ans;
}
if (rx<=midx && ly> midy)
{
ans=query(tree[now].ch[][],lx,rx,ly,ry);
return ans;
}
if (lx> midx && ry<=midy)
{
ans=query(tree[now].ch[][],lx,rx,ly,ry);
return ans;
}
if (lx> midx && ly> midy)
{
ans=query(tree[now].ch[][],lx,rx,ly,ry);
return ans;
}
if (rx<=midx)
{
ans=query(tree[now].ch[][],lx,rx,ly,midy);
ans+=query(tree[now].ch[][],lx,rx,midy+,ry);
return ans;
}
if (lx> midx)
{
ans=query(tree[now].ch[][],lx,rx,ly,midy);
ans+=query(tree[now].ch[][],lx,rx,midy+,ry);
return ans;
}
if (ry<=midy)
{
ans=query(tree[now].ch[][],lx,midx,ly,ry);
ans+=query(tree[now].ch[][],midx+,rx,ly,ry);
return ans;
}
if (ly> midy)
{
ans=query(tree[now].ch[][],lx,midx,ly,ry);
ans+=query(tree[now].ch[][],midx+,rx,ly,ry);
return ans;
}
ans=query(tree[now].ch[][],lx,midx,ly,midy);
ans+=query(tree[now].ch[][],lx,midx,midy+,ry);
ans+=query(tree[now].ch[][],midx+,rx,ly,midy);
ans+=query(tree[now].ch[][],midx+,rx,midy+,ry);
up(now);
return ans;
}
int main()
{
//freopen("input.txt","r",stdin);
int i,j,k;
int n,m;
int x,y,z;
char opt;
scanf("%c%d%d\n",&opt,&n,&m);
tree[].lx=;tree[].rx=n;
tree[].ly=;tree[].ry=m;
tree[].sum=tree[].lazy=;
topt=;
root=;
int a,b,c,d,e;
while (~scanf("%s",&opt))
{
if (opt=='L')
{
scanf("%d%d%d%d%d\n",&a,&b,&c,&d,&e);
add_val(root,a,c,b,d,e);
}else
{
scanf("%d%d%d%d\n",&a,&b,&c,&d);
printf("%d\n",query(root,a,c,b,d));
}
} }

二维线段书解法

tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树的更多相关文章

  1. 二维树状数组的区间加减及查询 tyvj 1716 上帝造题的七分钟

    详细解释见小结.http://blog.csdn.net/zmx354/article/details/31740985 #include <algorithm> #include < ...

  2. [luogu] P4514 上帝造题的七分钟 (树状数组,二维差分)

    P4514 上帝造题的七分钟 题目背景 裸体就意味着身体. 题目描述 "第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵. 第二分钟,L说,要能修改,于是便有了将左上角为(a ...

  3. BZOJ 3132: 上帝造题的七分钟( 二维BIT )

    二维树状数组... 自己YY一下再推一下应该可以搞出来... --------------------------------------------------------------------- ...

  4. 【bzoj3132】上帝造题的七分钟 二维树状数组区间修改区间查询

    题目描述 “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵. 第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作. ...

  5. BZOJ3132 上帝造题的七分钟 【二维树状数组】

    题目 "第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵. 第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的 ...

  6. 二维树状数组总结&&【洛谷P4514】 上帝造题的七分钟

    P4514 上帝造题的七分钟 题目描述 "第一分钟,X说,要有矩阵,于是便有了一个里面写满了00的n×mn×m矩阵. 第二分钟,L说,要能修改,于是便有了将左上角为(a,b)(a,b),右下 ...

  7. P4514 上帝造题的七分钟(二维树状数组)

    P4514 上帝造题的七分钟 二维树状数组 差分维护区间加法,区间求和 #include<cstdio> int read(){ ,f=; ') f=f&&(c!='-') ...

  8. TYVJ 1941 BZOJ3038 上帝造题的七分钟2 并查集+树状数组

    背景 XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部. 描述 "第一分钟,X说,要有数列,于是便给定了一个正整数数列. 第二分钟,L说,要能修改,于是便有了对一段数中每个 ...

  9. P4514 上帝造题的七分钟——二维树状数组

    P4514 上帝造题的七分钟 求的是矩阵里所有数的和: 维护四个树状数组: #include<cstdio> #include<cstring> #include<alg ...

随机推荐

  1. 64位开源处理器Rocket该人士介绍

    最近大概读一点UCB发布时间Rocket处理器的源代码,的每个文件的源代码的功能有一定的一般理解,Mark一点点. Rocket是一家64bit标量处理器,5第一阶段管道,用途risc-v指令集.综合 ...

  2. GCC扩展(转--对看kernel代码有帮助

    http://my.oschina.net/senmole/blog?catalog=153878 Linux Kernel的代码,上次就发现一个结构体的定义形式看不懂,后来才知道它用的不是标准的AN ...

  3. iOS开发大神必备的Xcode插件

    写在前面 工欲善其事,必先利其器,iOS开发中不仅要学会Xcode的基本操作,而且还得学会一些Xcode的使用技巧,如掌握常用的快捷键等,还有就是今天要说到的Xcode插件,下面我就为大家介绍几款开发 ...

  4. Java基础知识强化之集合框架笔记59:Map集合之TreeMap(TreeMap<String,String>)的案例

    1. TreeMap类的概述: 键是红黑树结构,可以保证键的排序和唯一性. 2. TreeMap案例: TreeMap<String, String> 代码示例: package cn.i ...

  5. Android(java)学习笔记169:Activity中的onCreate()方法分析

    1.onCreate( )方法是android应用程序中最常见的方法之一: 翻译过来就是说,onCreate()函数是在activity初始化的时候调用的,通常情况下,我们需要在onCreate()中 ...

  6. Microsoft Visual Studio Professional 2012 专业版 下载

    记录(以下内容来自网络收集): 下载地址: https://www.microsoft.com/zh-cn/download/details.aspx?id=30682 直接iso连接下载址: htt ...

  7. 两种隐藏元素方式【display: none】和【visibility: hidden】的区别

    此随笔的灵感来源于上周的一个面试,在谈到隐藏元素的时候,面试官突然问我[display: none]和[visibility: hidden]的区别,我当时一愣,这俩有区别吗,好像有,但是忘记了啊,因 ...

  8. <script runat=server>、<%%>和<%#%>的区别

    ①<script runat="server">代码段与<%%>内联代码段的区别 在asp.net页面的aspx文件中允许使用<script runa ...

  9. 给分类(Category)添加属性

    遇到一个问题,写了一个分类,但原先类的属性不够用.添加一个属性,调用的时候崩溃了,说是找不到getter.setter方法.查了下文档发现,OC的分类允许给分类添加属性,但不会自动生成getter.s ...

  10. 理解java Web项目中的路径问题

    本文以项目部署在tomcat服务器为例,其他相信也是一样的. 先说明请求页面的写法,在web中,页面路径主要写的有以下几种 1.请求重定向 2.浏览器的请求被服务器请求到新页面(我称为“转发”) 3. ...