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. 也谈android开发图像压缩

    long long ago,给学院做的一个通讯录App需要有一个上传图像的功能,冥思苦想,绞尽脑汁后来还是没解决(学生时代的事),于是就直接上传原图了,一张图片2M到3M,这样我的应用发布之后,那绝对 ...

  2. SVN状态图标不显示

    Windows最多只允许15个覆盖图标,它自己又用了几个,结果给用户用的就11个左右了,如果你安装了其他网盘,那可用的就更少了. 解决方法: 1.在运行里输入regedit进入注册表 2.依次打开HK ...

  3. C#面向对象(二)

    一:抽象方法 1. 在面向对象编程语言中抽象方法指一些只有方法声明,而没有具体方法体的方法.抽象方法一般存在于抽象类或接口中. 在一些父类中,某些行为不是非常明确,因此无法用代码来具体实现,但是类还必 ...

  4. JS实例(一)

    一:单选按钮,选择同意,提交变为可用,反正提交不可用: HTML里面代码: <form id="f1" name="f1"> <input t ...

  5. Android-关于屏幕适配的一些经验

    刚开始,我开发时选取的模拟器是WVGA854,其分辨率为854*480.我开发完毕后装在800*480的手机上时感觉很OK,但是装到480*320.以及320*240分辨率上的手机时,很多界面都变形了 ...

  6. javascript的面向对象编程

    面象对象编程技术的核心理念:封装.继承.多态:在一些主流的高级编程语言中,比如:C#,VB.NET,JAVA,PHP等都是很容易实现的,而如果要在javascript中实现面象对象编程,可就不那么直接 ...

  7. Android简单例子——IpHone样式AlertDialog

    此例子源于网络,下载下来之后,自己加了写注释,作为总结,发到博客中,谢谢原作者 通过这个例子学到的东西 1.自定义对话框的使用 2.程序中使用颜色如何进行存放,增加复用性 3.加深线性布局.常用控件的 ...

  8. html-----001

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. JS实时监听浏览器宽度的变化

    boot:function(){ //加载页面时执行一次 changeMargin(); //监听浏览器宽度的改变 window.onresize = function(){ changeMargin ...

  10. mysql主要应用场景 转载

    前言 据说目前MySQL用户已经达千万级别了,其中不乏企业级用户.可以说是目前最为流行的开源数据库管理系统软件了.任何产品都不可能是万能的,也不可能适用于所有的应用场景.那么MySQL到底在什么场景下 ...