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. ObjectDataProvider

    <Window.Resources> <ObjectDataProvider x:Key="personList" ObjectType="{x:Typ ...

  2. XF 定制图片

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. WPF 跨界面调用程序

    this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (System.Threading.ThreadStart)delegate() { sE ...

  4. JS超链接动态显示图片

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  5. 虚拟机安装的kali无法识别本机物联网卡

    http://blog.csdn.net/sb985/article/details/76427624

  6. datacontract helper

    public static class DataContractHelper { public static void ToDCFile<T>(this T obj, string pat ...

  7. 不能继承于QObject的类就一定不能使用信号槽?(用一个代理类进行发射就行了)

    首先不能继承QObject的情况在开发中遇到得并不多,笔者在一年多的Qt项目开发中只遇到两三次.而且都是因为引进了第三方库导致编译过程中报错. 要想解决这个问题其实不难,因为笔者遇到的问题都是想定义一 ...

  8. qmake.exe是在Qt安装编译时生成的,里面内嵌了Qt相关的一些路径(最简单的方法是保持一样的安装路径,最方便的办法是设置qt.conf文件)

    在网上直接下载别人编译好的Qt库,为自己使用省了不少事.但往往也会遇到些问题,其中Qt version is not properly installed,please run make instal ...

  9. Resolve conflict using "MERGE_HEAD (origin/HEAD)"

    Git进行同步的时候,经常会出现冲突,有时候冲突的选项会有图示中的三种选项: 1.Resolved:直接把文件标识为冲突已经解决,一般是自己手动查看并解决完冲突以后使用. 2.Resolve conf ...

  10. 安卓ImageButton圆角按钮设置

    首先图片要做成圆角的,使用美图秀秀,这个不多说. 之后使用设置了圆角的按钮,效果有缺陷,按钮会有灰色的边角. 类似这样: 去掉的方法是将layout的  android:src="@draw ...