二维线段树->树套树
现在上真正的二维线段树 毕竟 刚刚那个是卡常 过题我们现在做一个更高级的做法二维线段树。
大体上维护一颗x轴线段树 然后在每个节点的下方再吊一颗维护y轴的线段树那么此时我们整个平面就被我们玩好了。
这样形成二维线段树比刚才的要 合理多了。
写起来 不免有点蒙蔽...然后突然就顿悟了 其实每次我们对于区间的修改大概就是先把x属于x轴的那一段区间给拎出来然后在那个区间之中把那个区间的y轴线段树给修改掉。

还是刚刚那道题 这次是MLE 了 理论上二维线段树空间复杂度 (MAXN<<2)^2这个复杂度 可是正中下怀的MLE了 开小了一点就可以过了。
//#include<bits/stdc++.h>
#include<iostream>
#include<iomanip>
#include<ctime>
#include<cstring>
#include<string>
#include<ctime>
#include<cctype>
#include<cstdio>
#include<utility>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<set>
#include<bitset>
#include<vector>
#include<algorithm>
#include<cstdlib>
#define INF 1000000000
#define ll long long
#define mx(p) t[p].mx
#define tag(p) t[p].tag
#define RE register
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
RE int x=,f=;RE char ch=getc();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getc();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getc();}
return x*f;
}
const int MAXN=;
int n,m,Q;
int qx,xx,qy,yy,h;
inline int max(int x,int y){return x>y?x:y;}
struct wy
{
int mx[MAXN],tag[MAXN];
inline void change(int p,int l,int r,int x,int y,int k)
{
mx[p]=max(mx[p],k);
if(l==x&&r==y)
{
tag[p]=max(tag[p],k);
return;
}
int mid=(l+r)>>;
if(y<=mid)change(p<<,l,mid,x,y,k);
else
{
if(x>mid)change(p<<|,mid+,r,x,y,k);
else change(p<<,l,mid,x,mid,k),change(p<<|,mid+,r,mid+,y,k);
}
}
inline int ask(int p,int l,int r,int x,int y)
{
if(l==x&&r==y)return mx[p];
int mid=(l+r)>>,ans=tag[p];
if(y<=mid)ans=max(ans,ask(p<<,l,mid,x,y));
else
{
if(x>mid)ans=max(ans,ask(p<<|,mid+,r,x,y));
else ans=max(ans,max(ask(p<<,l,mid,x,mid),ask(p<<|,mid+,r,mid+,y)));
}
return ans;
}
};
struct tx
{
wy mx[MAXN],tag[MAXN];
inline void change(int p,int l,int r,int x,int y,int k)
{
mx[p].change(,,m,qy,yy,k);
if(l==x&&r==y)
{
tag[p].change(,,m,qy,yy,k);
return;
}
int mid=(l+r)>>;
if(y<=mid)change(p<<,l,mid,x,y,k);
else
{
if(x>mid)change(p<<|,mid+,r,x,y,k);
else change(p<<,l,mid,x,mid,k),change(p<<|,mid+,r,mid+,y,k);
}
}
inline int ask(int p,int l,int r,int x,int y)
{
if(l==x&&r==y)return mx[p].ask(,,m,qy,yy);
int mid=(l+r)>>,ans=tag[p].ask(,,m,qy,yy);
if(y<=mid)ans=max(ans,ask(p<<,l,mid,x,y));
else
{
if(x>mid)ans=max(ans,ask(p<<|,mid+,r,x,y));
else
{
ans=max(ans,ask(p<<,l,mid,x,mid));
ans=max(ans,ask(p<<|,mid+,r,mid+,y));
}
}
return ans;
}
}T;
int main()
{
freopen("1.in","r",stdin);
n=read();m=read();Q=read();
while(Q--)
{
xx=read();yy=read();h=read();
qx=read()+;qy=read()+;
xx=qx+xx-;yy=qy+yy-;
int ans=T.ask(,,n,qx,xx);
T.change(,,n,qx,xx,ans+h);
}
qx=;qy=;xx=n;yy=m;
printf("%d\n",T.ask(,,n,qx,xx));
return ;
}
操作还是不太熟悉 觉得这个可持久化有点神仙没写过有点 怀疑 不过正确性 和 合理性都是比较显然的。
简述一下大体的思路吧 首先对x轴开一棵线段树然后 在x轴的这颗线段树每个节点处都吊着一棵y轴的线段树。
下传修改标记 的时候 对于到过路径上的所有的节点都应该修改值 因为这是标记所致 到了锁定的区间之后标记永久化 对这个tag打上标记 而对内部的y轴线段树也进行一次标记永久化。
通俗的来说 内外线段树处理方式一模一样。为什么不能下传标记 显然的是我们对于外层线段树的修改 在自己的内部是无法下传的 因为标记是无法合并的 比如说 ta 要修改1 n 1 2这个区间ta又要修改1 n 1 3这个区间显然这两个区间在x线段树上是对等的在y线段树上可并不对等所以这两个标记很难合并 故应该标记永久化减少合并的麻烦。
这里我们很完美的解决了 二维线段树的问题。 单次操作时间显然是 logn^2.
二维线段树->树套树的更多相关文章
- poj 2155 matrix 二维线段树 线段树套线段树
题意 一个$n*n$矩阵,初始全为0,每次翻转一个子矩阵,然后单点查找 题解 任意一种能维护二维平面的数据结构都可以 我这里写的是二维线段树,因为四分树的写法复杂度可能会退化,因此考虑用树套树实现二维 ...
- BZOJ.4553.[HEOI2016&TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)
题目链接:BZOJ 洛谷 \(O(n^2)\)DP很好写,对于当前的i从之前满足条件的j中选一个最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++j) if(a[ ...
- UVA 11297 线段树套线段树(二维线段树)
题目大意: 就是在二维的空间内进行单个的修改,或者进行整块矩形区域的最大最小值查询 二维线段树树,要注意的是第一维上不是叶子形成的第二维线段树和叶子形成的第二维线段树要 不同的处理方式,非叶子形成的 ...
- HDU 4819 Mosaic --二维线段树(树套树)
题意: 给一个矩阵,每次查询一个子矩阵内的最大最小值,然后更新子矩阵中心点为(Max+Min)/2. 解法: 由于是矩阵,且要求区间最大最小和更新单点,很容易想到二维的线段树,可是因为之前没写过二维的 ...
- HDU 1823 Luck and Love 二维线段树(树套树)
点击打开链接 Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- 【BZOJ4785】[Zjoi2017]树状数组 树套树(二维线段树)
[BZOJ4785][Zjoi2017]树状数组 Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一 ...
- poj 1195:Mobile phones(二维线段树,矩阵求和)
Mobile phones Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 14391 Accepted: 6685 De ...
- HDU 4819 Mosaic(13年长春现场 二维线段树)
HDU 4819 Mosaic 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4819 题意:给定一个n*n的矩阵,每次给定一个子矩阵区域(x,y,l) ...
- 洛谷.3437.[POI2006]TET-Tetris 3D(二维线段树)
题目链接 下落一个d*s的方块,则要在这个平面区域找一个最高的h' 更新整个平面区域的值为h+h' 对于本题,维护最大高度h和all 对于平面的x轴维护一棵线段树t1,每个t1的节点维护对应y轴的两棵 ...
随机推荐
- 深入理解letter-spacing,word-spacing的对比区别
letter-spacing lletter-spacing 属性增加或减少字符间的空白(字符间距). 该属性定义了在文本字符框之间插入多少空间.由于字符字形通常比其字符框要窄,指定长度值时,会调整字 ...
- pdf流文件转图片
需求:将后台返回的pdf流文件转换成图片与页面其他内容一起打印pdf流文件不能直接在前台显示,需要借助pdf.js+viewer.js. 一般情况下,如果要打印pdf流文件,可以直接在新打开的view ...
- C# 基于内容电影推荐项目(一)
从今天起,我将制作一个电影推荐项目,在此写下博客,记录每天的成果. 其实,从我发布 C# 爬取猫眼电影数据 这篇博客后, 我就已经开始制作电影推荐项目了,今天写下这篇博客,也是因为项目进度已经完成50 ...
- JAVA的8种基本数据类型分析
基本数据类型(8个) 1.整数类型(4个) 字节个数 取值范围 byte(字节) 1(8位) -2^7~2^7-1 short(短整型) 2(16位) -2^15~2^15-1 int(整形) 4 ...
- C/C++代码覆盖率统计工具:gcov&&gcovr安装和简单使用
gcov安装 Linux ver: gcov是gcc的自带功能 属于GNU 不用特别安装 Windows ver: 在windows下安装可以使用gcov的gcc 之前试过mingw和Cygwin64 ...
- mysql常用时间函数与类型转换
一.用到的函数有: 1.时间格式化函数 DATE_FORMAT(date,format) 2.时间加减函数DATE_ADD(date,INTERVAL expr unit)DATE_SUB(date ...
- Zookeeper是什么&怎么用
1.Zookeeper概述 Zookeeper 是一个开源的分布式协调服务框架 ,主要用来解决分布式集群中应用系统的一致性问题和数据管理问题 2:Zookeeper的特点 Zookeeper 本质上是 ...
- Maven 专题(四):什么是Maven
1 Maven 简介 Maven 是 Apache 软件基金会组织维护的一款自动化构建工具,专注服务于 Java 平台的项目构建和 依赖管理.Maven 这个单词的本意是:专家,内行.读音是['meɪ ...
- C++算法 链式前向星存图
这个东西恶心了我一阵子,那个什么是什么的上一个一直是背下来的,上次比赛忘了,回来有个题也要用,只能再学一遍,之前也是,不会为什么不学呢.我觉得是因为他们讲的不太容易理解,所以我自己给那些不会的人们讲一 ...
- PowerJob 技术综述,能领悟多少就看你下多少功夫了~
本文适合有 Java 基础知识的人群 作者:HelloGitHub-Salieri HelloGitHub 推出的<讲解开源项目>系列.从本章开始,就正式进入 PowerJob 框架的技术 ...