http://acm.hdu.edu.cn/showproblem.php?pid=4819

题意:给出一个矩阵,然后q个询问,每个询问有a,b,c,代表(a,b)这个点上下左右c/2的矩形区域内的(最大值+最小值)/2是多少,并且将(a,b)的值替换成这个答案。

思路:很久以前被暴力跑过去的一道题,今天怎么交也过不去。。。果然是人品爆发了。

学了一下树套树,一开始觉得挺容易理解,但是后面PushUp那里挺难懂的(对我来说)。

我的理解:

对于每个线段树的结点开一棵线段树,即tree[x][y],x代表的是行的信息,y代表的是列的信息。

觉得PushUp难懂的原因是不知道行上的非叶子结点和列上的非叶子结点是怎么更新的。

 void PushUp1(int x, int y) {
tree[x][y].small = min(tree[x<<][y].small, tree[x<<|][y].small);
tree[x][y].big = max(tree[x<<][y].big, tree[x<<|][y].big);
} void PushUp2(int x, int y) {
tree[x][y].small = min(tree[x][y<<].small, tree[x][y<<|].small);
tree[x][y].big = max(tree[x][y<<].big, tree[x][y<<|].big);
} void Update1(int x, int leaf, int rt, int l, int r, int id, int val) {
if(l == r) {
if(leaf) { tree[x][rt].small = tree[x][rt].big = val; return ; }
PushUp1(x, rt); // 列相同的时候并且行不是叶子结点的时候去更新行的线段树的状态
return ;
}
int m = (l + r) >> ;
if(id <= m) Update1(x, leaf, lson, id, val);
else Update1(x, leaf, rson, id, val);
PushUp2(x, rt);
} void Update2(int rt, int l, int r, int xx, int yy, int val) {
if(l == r) {
Update1(rt, , , , n, yy, val);
return ;
}
int m = (l + r) >> ;
if(xx <= m) Update2(lson, xx, yy, val);
else Update2(rson, xx, yy, val);
Update1(rt, , , , n, yy, val);
}

首先看Update2,这是更新行的线段树信息,和普通线段树一样,只不过是普通的PushUp改成了Update1,插入操作改成了Update1,因此理解Update1就好了。

对于既是列的叶子结点又是行的叶子结点的结点,是对应于矩阵一个点的结点,因此对其赋值修改。

对于是列的叶子结点但是不是行的叶子结点的结点,我们将其行的信息像平时维护一维线段树一样,将行的信息PushUp。

对于不是列的叶子结点的结点,它可以储存列的区间信息,因此将列的信息PushUp。

那么像我之前的疑问,即不是列的叶子结点又不是行的叶子结点的信息在哪里维护。。。

注意原本的PushUp操作变成了Update1,即对于每个行结点,都会去更新对应的那棵线段树,而且是从底向上,因此信息都会被更新。

还优化了一下一开始的读入插入,用类似于Update的Build函数,可以在Build的时候行为叶子列为叶子的时候读入,这样操作为O(n^2)的复杂度,普通的Update插入需要O(n^2 logn^2),跑之后快了一倍的时间。

下面是所有代码:

 #include <bits/stdc++.h>
using namespace std;
#define N 800
#define INF 1000000007
#define lson rt<<1, l, m
#define rson rt<<1|1, m + 1, r
struct node {
int small, big;
} tree[N<<][N<<];
int big, small, n; void PushUp1(int x, int y) {
tree[x][y].small = min(tree[x<<][y].small, tree[x<<|][y].small);
tree[x][y].big = max(tree[x<<][y].big, tree[x<<|][y].big);
} void PushUp2(int x, int y) {
tree[x][y].small = min(tree[x][y<<].small, tree[x][y<<|].small);
tree[x][y].big = max(tree[x][y<<].big, tree[x][y<<|].big);
} void Build1(int x, int leaf, int rt, int l, int r) {
if(l == r) {
if(leaf) { scanf("%d", &tree[x][rt].big), tree[x][rt].small = tree[x][rt].big; return ; }
PushUp1(x, rt); return ;
}
int m = (l + r) >> ;
Build1(x, leaf, lson); Build1(x, leaf, rson);
PushUp2(x, rt);
} void Build2(int rt, int l, int r) {
if(l == r) { Build1(rt, , , , n); return ; }
int m = (l + r) >> ;
Build2(lson); Build2(rson);
Build1(rt, , , , n);
} void Query1(int x, int rt, int l, int r, int y1, int y2) {
if(y1 <= l && r <= y2) {
big = max(big, tree[x][rt].big);
small = min(small, tree[x][rt].small);
return ;
}
int m = (l + r) >> ;
if(y1 <= m) Query1(x, lson, y1, y2);
if(m < y2) Query1(x, rson, y1, y2);
} void Query2(int rt, int l, int r, int x1, int x2, int y1, int y2) {
if(x1 <= l && r <= x2) {
Query1(rt, , , n, y1, y2);
return ;
}
int m = (l + r) >> ;
if(x1 <= m) Query2(lson, x1, x2, y1, y2);
if(m < x2) Query2(rson, x1, x2, y1, y2);
} void Update1(int x, int leaf, int rt, int l, int r, int id, int val) {
if(l == r) {
if(leaf) { tree[x][rt].small = tree[x][rt].big = val; return ; }
PushUp1(x, rt); // 列相同的时候并且行不是叶子结点的时候去更新行的线段树的状态
return ;
}
int m = (l + r) >> ;
if(id <= m) Update1(x, leaf, lson, id, val);
else Update1(x, leaf, rson, id, val);
PushUp2(x, rt);
} void Update2(int rt, int l, int r, int xx, int yy, int val) {
if(l == r) {
Update1(rt, , , , n, yy, val);
return ;
}
int m = (l + r) >> ;
if(xx <= m) Update2(lson, xx, yy, val);
else Update2(rson, xx, yy, val);
Update1(rt, , , , n, yy, val);
} int main() {
int t; scanf("%d", &t);
for(int cas = ; cas <= t; cas++) {
scanf("%d", &n);
Build2(, , n);
int q; scanf("%d", &q);
printf("Case #%d:\n", cas);
while(q--) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
int x1 = max(, a - c / ), x2 = min(n, a + c / );
int y1 = max(, b - c / ), y2 = min(n, b + c / );
big = -INF, small = INF;
Query2(, , n, x1, x2, y1, y2);
int now = (big + small) / ;
printf("%d\n", now);
Update2(, , n, a, b, now);
}
}
return ;
}

HDU 4819:Mosaic(线段树套线段树)的更多相关文章

  1. HDU 4819 Mosaic (二维线段树)

    Mosaic Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)Total S ...

  2. HDU 4819 Mosaic (二维线段树&区间最值)题解

    思路: 二维线段树模板题,马克一下,以后当模板用 代码: #include<cstdio> #include<cmath> #include<cstring> #i ...

  3. HDU 4819 Mosaic 【二维线段树】

    题目大意:给你一个n*n的矩阵,每次找到一个点(x,y)周围l*l的子矩阵中的最大值a和最小值b,将(x,y)更新为(a+b)/2 思路:裸的二维线段树 #include<iostream> ...

  4. HDU 4819 Mosaic(13年长春现场 二维线段树)

    HDU 4819 Mosaic 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4819 题意:给定一个n*n的矩阵,每次给定一个子矩阵区域(x,y,l) ...

  5. hdu-4819-线段树套线段树

    http://acm.hdu.edu.cn/showproblem.php?pid=4819 给出一个N*N的矩阵,每次询问一个m*m的子矩阵里的floor((maxv+minv)/2)并把中间的元素 ...

  6. bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1807  Solved: 772[Submit][Stat ...

  7. [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  8. ZJOI 2017 树状数组(线段树套线段树)

    题意 http://uoj.ac/problem/291 思路 不难发现,九条カレン醬所写的树状数组,在查询区间 \([1,r]\) 的时候,其实在查询后缀 \([r,n]\) :在查询 \([l,r ...

  9. BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)

    题目描述 Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的 ...

  10. dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448

    4448: [Scoi2015]情报传递 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 588  Solved: 308[Submit][Status ...

随机推荐

  1. Angular路由守卫 canActivate

    作用 canActivate 控制是否允许进入路由. canActivateChild 等同 canActivate,只不过针对是所有子路由. 关键代码 创建路由守卫 import { Injecta ...

  2. 在实现视频播放器的步骤client(三)风行网络电影列表

    (三) 今日热门电影实现这个功能.主要从server获取数据.然后显示在屏幕上.虽然说是从这个server获取电影信息数据,但,不实际的http相关知识,我们直接sdk包(56网络提供api),你将能 ...

  3. Angular语法(一)——展示数据

    双花括号{{}} 展示数据 title = 'Tour of Heroes'; myHero = 'Windstorm'; <h1>{{title}}</h1> <h2& ...

  4. Delphi中返回类型为string的函数的一个陷阱(不是很懂)

    如果类的一个成员函数的返回值是string类型,需要注意一个问题 其返回值可能是错误的 例如函数的实现如下 function GetString( s: string ): string;begin  ...

  5. Z-Order

    The z-order of a window indicates the window's position in a stack of overlapping windows. This wind ...

  6. 使用sklearn构建含有标量属性的决策树

    网络上使用sklearn生成决策树的资料很多,这里主要说明遇见标量数据的处理. 经查验参考资料,sklearn并非使用了课上以及书上讲的ID3算法,而是选择了CART,该算法生成二叉树:scikit- ...

  7. PySide——Python图形化界面入门教程(五)

    PySide——Python图形化界面入门教程(五) ——QListWidget 翻译自:http://pythoncentral.io/pyside-pyqt-tutorial-the-qlistw ...

  8. Linux杂谈: 树形显示多级目录--tree

    最近写博客的时候偶尔会需要将文件目录结构直观地列出来,例如python的包结构. 于是在网上搜了搜,发现了一个Linux下还不错的工具--tree tree 可以很直观地显示多级目录结构. 1. 安装 ...

  9. 微信小程序把玩(九)scroll-view组件

    原文:微信小程序把玩(九)scroll-view组件 scroll-view为滚动视图,分为水平滚动和垂直滚动.注意滚动视图垂直滚动时一定要设置高度否则的话scroll-view不会生效.滚动视图常用 ...

  10. Android零基础入门第5节:善用ADT Bundle,轻松邂逅女神

    原文:Android零基础入门第5节:善用ADT Bundle,轻松邂逅女神 在前几期中总结分享了Android的前世今生.Android 系统架构和应用组件那些事.带你一起来聊一聊Android开发 ...