HDU 4819:Mosaic(线段树套线段树)
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(线段树套线段树)的更多相关文章
- HDU 4819 Mosaic (二维线段树)
Mosaic Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others)Total S ...
- HDU 4819 Mosaic (二维线段树&区间最值)题解
思路: 二维线段树模板题,马克一下,以后当模板用 代码: #include<cstdio> #include<cmath> #include<cstring> #i ...
- HDU 4819 Mosaic 【二维线段树】
题目大意:给你一个n*n的矩阵,每次找到一个点(x,y)周围l*l的子矩阵中的最大值a和最小值b,将(x,y)更新为(a+b)/2 思路:裸的二维线段树 #include<iostream> ...
- HDU 4819 Mosaic(13年长春现场 二维线段树)
HDU 4819 Mosaic 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4819 题意:给定一个n*n的矩阵,每次给定一个子矩阵区域(x,y,l) ...
- hdu-4819-线段树套线段树
http://acm.hdu.edu.cn/showproblem.php?pid=4819 给出一个N*N的矩阵,每次询问一个m*m的子矩阵里的floor((maxv+minv)/2)并把中间的元素 ...
- bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1807 Solved: 772[Submit][Stat ...
- [BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】
题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...
- ZJOI 2017 树状数组(线段树套线段树)
题意 http://uoj.ac/problem/291 思路 不难发现,九条カレン醬所写的树状数组,在查询区间 \([1,r]\) 的时候,其实在查询后缀 \([r,n]\) :在查询 \([l,r ...
- BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)
题目描述 Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的 ...
- dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448
4448: [Scoi2015]情报传递 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 588 Solved: 308[Submit][Status ...
随机推荐
- 网络库Asio交叉编译(Linux生成ARM)
1. Asio是一个跨平台的C++库,用于网络和底层I/O编程.Asio使用先进的C++方式提供了一系列的异步模型 2. 官方网址:http://think-async.com 3. 由于Asio库 ...
- C#控制台关闭之前做一些操作
using System; using System.Runtime.InteropServices; class Program { static void Main(string[] args) ...
- WPF 拖动多个文件到窗体 添加文件信息
将Window的AllowDrop属性设置为true window添加Drop事件 private void Window_Drop(object sender, DragEventArgs e) { ...
- WPF Binding妙处-既无Path也无Source
<Window x:Class="XamlTest.Window12" xmlns="http://schemas.microsoft.com/win ...
- Gralde 网络代理
Gralde 网络代理 Gradle在编译项目的时候,需要下载一些依赖.墙外的网络就需要设置代理了. 设置的方法,见文档: Accessing the web through a HTTP proxy ...
- 生成wsdl代理c#代码
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\wsdl.exe /l:CS /out:d:\ws ...
- 管道通信实例(A程序作为服务器,不断从B程序接收数据,并发送到C程序中)
A程序作为服务器,不断从B程序接收数据,并发送到C程序中:#include <stdio.h>#include <conio.h> #include <tchar.h&g ...
- DIOCP3 DEMO的编译(去掉VCL前缀)
总有些朋友问我,关于DEMO编译的一些问题,每次都回答大概都差不多,我想还是写篇说明书给大家,关于DEMO编译的步骤. [环境设定] 1.将DIOCP3\source路径添加到Delphi的搜索路径, ...
- 虚拟化代码博客 good
推荐网站和博客地址 -------------------------------- 虚拟化代码博客 QEMU大牛博客:qemu - 韋任的維基百科 http://people.cs.nctu ...
- LeetCode : Given a string, find the length of the longest serial substring without repeating characters.
Given a string, find the length of the longest serial substring without repeating characters. Exampl ...