【BZOJ 2957】楼房重建&&Codechef COT5 Count on a Treap&&【NOIP模拟赛】Weed 线段树的分治维护
线段树是一种作用于静态区间上的数据结构,可以高效查询连续区间和单点,类似于一种静态的分治。他最迷人的地方在于“lazy标记”,对于lazy标记一般随我们从父区间进入子区间而下传,最终给到叶子节点,但还有一种做法就是对于作用域一整个区间的标记,就将其放置在此区间节点,查询时再结算其贡献,但无论怎样我们都要保证我们查询到的区间信息的真实性完整性,这就意味着我们接触一个区间若要了解到他的全部有用信息,并不用进入其下层区间(以上两种标记方式往往再结合出现时有巧妙的用处)。于是我们必须高效地合并子区间的信息以维护此区间的信息,对于多数信息我们可以在O(1)时间内高效完成,但是有一些时候我们的合并并不顺利,并不能直接结算,这个时候我们会多记录一些附加信息来便于合并,但是如果这样行不通我们还有另外一种高效的方式,就是在合并的时候我们再对子区间进行分治(往往利用线段树静态分治的天然优势),如果能得到O(log)的复杂度(或者其他可以接受的复杂度),那么就是可行的,这种方法在题目中的三道题中均有应用。
关于【BZOJ 2957】楼房重建,比较裸,直接讲解下两道。懒的说了
Codechef COT5 Count on a Treap
关于这道题你一看题干就不能去打Treap。我们想一想笛卡尔树,那么我们就把这些点用key值(二叉树)排序,然后发现得到的区间里,如果用val值(堆)从大到小切割区间,就得到了我们想要的Treap。两个数之间的最大值(val)就他们的lca,那么我们又发现,每个点向两边的上升序列长度和就是他的深度,这样我们就得到了一种可行方案,现在我们就是要找上升序列列长度,方法同上题。
#pragma GCC optimize("O3")
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mid ((l+r)>>1)
typedef long long LL;
const LL N=;
typedef std::pair<LL,LL> pii;
struct Segment_Tree{
Segment_Tree *ch[];
int zlen,ylen,pos;LL max;
inline void pushup(){
if(ch[]->max>ch[]->max) max=ch[]->max,pos=ch[]->pos;
else max=ch[]->max,pos=ch[]->pos;
}
}*root,node[N<<];
int n,sz,T;LL q[N][];
pii poi[N];
inline void build(Segment_Tree *&p,int l,int r){
p=node+(sz++),p->zlen=p->ylen=;
if(l==r){p->max=,p->pos=l;return;}
build(p->ch[],l,mid),build(p->ch[],mid+,r);
p->pushup();
}
inline int zcalc(Segment_Tree *p,int l,int r,LL max){
if(p==NULL||p->max<=max)return ;
if(l==r)return p->max>max;
if(p->ch[]->max<=max)return zcalc(p->ch[],mid+,r,max);
else return zcalc(p->ch[],l,mid,max)+p->zlen-p->ch[]->zlen;
}
inline int ycalc(Segment_Tree *p,int l,int r,LL max){
if(p==NULL||p->max<=max)return ;
if(l==r)return p->max>max;
if(p->ch[]->max<=max)return ycalc(p->ch[],l,mid,max);
else return ycalc(p->ch[],mid+,r,max)+p->ylen-p->ch[]->ylen;
}
inline void U(Segment_Tree *p,int l,int r,int pos,LL val){
if(l==r){p->max=val;return;}
if(pos<=mid)U(p->ch[],l,mid,pos,val);
else U(p->ch[],mid+,r,pos,val);
p->pushup();
p->zlen=p->ch[]->zlen+zcalc(p->ch[],mid+,r,p->ch[]->max);
p->ylen=p->ch[]->ylen+ycalc(p->ch[],l,mid,p->ch[]->max);
}
inline pii Q(Segment_Tree *p,int l,int r,int z,int y){
if(z<=l&&r<=y)return std::make_pair(p->max,p->pos);
pii ret=std::make_pair(-,-),temp;
if(z<=mid)temp=Q(p->ch[],l,mid,z,y);
if(temp.first>ret.first)ret=temp;
if(mid<y)temp=Q(p->ch[],mid+,r,z,y);
if(temp.first>ret.first)ret=temp;
return ret;
}
inline void Qz(Segment_Tree *p,int l,int r,int z,int y,int &ans,LL &max){
if(z<=l&&r<=y){ans+=zcalc(p,l,r,max),max=std::max(max,p->max);return;}
if(z<=mid)Qz(p->ch[],l,mid,z,y,ans,max);
if(mid<y)Qz(p->ch[],mid+,r,z,y,ans,max);
}
inline void Qy(Segment_Tree *p,int l,int r,int z,int y,int &ans,LL &max){
if(z<=l&&r<=y){ans+=ycalc(p,l,r,max),max=std::max(max,p->max);return;}
if(mid<y)Qy(p->ch[],mid+,r,z,y,ans,max);
if(z<=mid)Qy(p->ch[],l,mid,z,y,ans,max);
}
inline int Q(int pos){
int ret=,ans=;LL max=poi[pos].second;
if(pos!=)Qy(root,,n,,pos-,ans,max);
ret+=ans,ans=,max=poi[pos].second;
if(pos!=n)Qz(root,,n,pos+,n,ans,max);
ret+=ans;return ret;
}
int main(){
scanf("%d",&T);for(int i=;i<=T;++i){
scanf("%lld",&q[i][]);
if(q[i][]&)scanf("%lld",&q[i][]);
else scanf("%lld%lld",&q[i][],&q[i][]);
if(q[i][]==)poi[++n]=std::make_pair(q[i][],q[i][]);
}
std::sort(poi+,poi+(n+)),build(root,,n);
for(int i=,pos,l,r,mi;i<=T;++i)
switch(q[i][]){
case :
pos=std::lower_bound(poi+,poi+(n+),std::make_pair(q[i][],0LL))-poi;
U(root,,n,pos,q[i][]);break;
case :
pos=std::lower_bound(poi+,poi+(n+),std::make_pair(q[i][],0LL))-poi;
U(root,,n,pos,);break;
case :
l=std::lower_bound(poi+,poi+(n+),std::make_pair(q[i][],0LL))-poi;
r=std::lower_bound(poi+,poi+(n+),std::make_pair(q[i][],0LL))-poi;
if(l>r)l^=r^=l^=r;mi=Q(root,,n,l,r).second;
printf("%d\n",Q(l)+Q(r)-Q(mi)*);break;
}
}
Codechef COT5 Count on a Treap
【NOIP模拟赛】Weed
这道题十分巧妙,我们在线段树上记录三个值,要删之前的多少点,剩下多少点,剩下多少东西,然后单点修改,查询root,维护同理。
#pragma GCC optimize("O3")
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mid ((l+r)>>1)
const int N=;
inline void read(int &sum){
register char ch=getchar();
for(sum=;ch<''||ch>'';ch=getchar());
for(;ch>=''&&ch<='';sum=(sum<<)+(sum<<)+ch-'',ch=getchar());
}
struct Segment_Tree{
Segment_Tree *ch[];
int del,sum,num;
}*root,node[N<<];
int sz,n,m;
inline void build(Segment_Tree *&p,int l,int r){
p=node+(sz++);if(l==r)return;
build(p->ch[],l,mid),build(p->ch[],mid+,r);
}
inline int Q(Segment_Tree *p,int l,int r,int del){
if(p->num<=del)return ;
if(l==r)return p->sum;
if(p->ch[]->num>=del)return p->sum-p->ch[]->sum+Q(p->ch[],mid+,r,del);
else return Q(p->ch[],l,mid,del-p->ch[]->num+p->ch[]->del);
}
inline void U(Segment_Tree *p,int l,int r,int pos,int key,int opt){
if(l==r){
if(opt)p->sum=,p->num=,p->del=key;
else p->del=,p->num=,p->sum=key;
return;
}
if(pos<=mid)U(p->ch[],l,mid,pos,key,opt);
else U(p->ch[],mid+,r,pos,key,opt);
if(p->ch[]->num<=p->ch[]->del)
p->del=p->ch[]->del+p->ch[]->del-p->ch[]->num,p->sum=p->ch[]->sum,p->num=p->ch[]->num;
else
p->del=p->ch[]->del,p->num=p->ch[]->num+p->ch[]->num-p->ch[]->del,
p->sum=p->ch[]->sum+Q(p->ch[],l,mid,p->ch[]->del);
}
int main(){
read(n),read(m),build(root,,n);
for(int i=,x,y;i<=n;++i)
read(x),read(y),U(root,,n,i,y,x);
int pos,opt,key;
while(m--){
read(pos),read(opt),read(key);
U(root,,n,pos,key,opt);
printf("%d\n",root->sum);
}
}
【NOIP模拟赛】Weed
【BZOJ 2957】楼房重建&&Codechef COT5 Count on a Treap&&【NOIP模拟赛】Weed 线段树的分治维护的更多相关文章
- BZOJ 2957楼房重建
传送门 线段树 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include< ...
- bzoj 2957: 楼房重建 线段树
2957: 楼房重建 Time Limit: 10 Sec Memory Limit: 256 MB[Submit][Status][Discuss] Description 小A的楼房外有一大片施 ...
- bzoj 2957 楼房重建 分块
楼房重建 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=29 ...
- [BZOJ 2957]楼房重建(THU2013集训)(线段树维护单调栈)
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2957 分析: 根据题意,就是比较斜率大小 只看一段区间的话,那么这段区间能看见的楼房数量就是这 ...
- BZOJ 2957 楼房重建 (线段树)
题目链接 楼房重建 解题思路:我们可以把楼房的最高点的斜率计算出来.那么问题就转化成了实时查询x的个数,满足数列x的左边没有大于等于x的数. 我们可以用线段树维护 设t[i]为如果只看这个区间,可以 ...
- 洛谷 P4198 BZOJ 2957 楼房重建
题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个 ...
- BZOJ 2957 楼房重建
Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...
- bzoj 2957 楼房重建 (线段树+思路)
链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2957 思路: 用分块可以很简单的过掉,但是这道题也可以用线段树写. 分类讨论左区间最大值对 ...
- bzoj 2957: 楼房重建 ——线段树
Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...
随机推荐
- [转]JavaScript中的匿名函数及函数的闭包
JavaScript中的匿名函数及函数的闭包 原文地址:http://www.cnblogs.com/wl0000-03/p/6050108.html 1.匿名函数 函数是JavaScript中最灵 ...
- JavaSE库存管理系统项目实战
需求分析 企业库房用于存放成品.半成品.原材料.工具等物资,一般情况下,这些物资统称为物料.库存管理常见业务包括物资的入库.出库.盘点.退货.报废以及财务核算等,业务逻辑比较复杂,库房信息系统项目开发 ...
- 初识python 函数(定义,传参,返回值)
python基础(二): 菜鸟教程基础知识讲解的非常全面,内容选择我认为的重点输出一遍 函数: 定义一个函数: 你可以定义一个由自己想要功能的函数,以下是简单的规则: def fun(arg): pa ...
- 用intellij Idea加载eclipse的maven项目全流程
eclipse的maven项目目录 全流程 加载项目 打开intellij Idea file -> new -> module from existing Sources 选择.pom ...
- C++基础语言知识大汇总(不断更新!!!)
经过十天的时间,LITTLESUN做好了前期的工作,今天LITTLESUN就要在新地图里扬帆起航喽!!!(撒花) 简单的整理了一下这次启航准备好的物资.后面的航程中也会不断来补充这个小仓库哦!
- 配置ORACLE的PRO*C环境
1.访问数据库的方法 在ORACLE数据库管理和系统中,有三种访问数据库的方法: ⑴.用SQL*Plus, 它有SQL命令以交互的应用程序访问数据库: ⑵.用第四代语言应用开发工具开 ...
- 自定义T4模板去掉实体对象中的下划线
在EF Power Tool 默认使用的T4模板中,如果数据库表有下划线,那么生成的实体也有下划线,但是我们实际使用的过程中,是不希望有下划线的,要解决这个问题,可以自定义这个T4模板 ...
- 关于transition动画下,如果有fixed元素,渲染的奇葩问题
之前我们机票页面有生成一个低价日历,然后我们有一个需求就是滚动到那个月份,对应显示这个月,然后这个区域是fixed定位的,然后奇怪的事情发生了,就是低价日历的动画执行完后,修改页面的html却没有正常 ...
- 『MongoDB』集合更新操作
参考 定义 db.collection.update(query, update, options) 改变一个在集合中已经存在的文档或文档数组.默认的,update()方法更新一个独立的文档.如果mu ...
- Windows Server2003下安装IIS服务脑图
在练习过程中,勾选“ASP.NET”后开始安装时提示要插入安装光盘,但是我安装系统时是用镜像文件在虚拟机里安装的,所以根据提示界面的提示从文件中选择相应文件复制,如下图点击确定,选择iisapp.vb ...