线段树是一种作用于静态区间上的数据结构,可以高效查询连续区间和单点,类似于一种静态的分治。他最迷人的地方在于“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 线段树的分治维护的更多相关文章

  1. BZOJ 2957楼房重建

    传送门 线段树 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> #include< ...

  2. bzoj 2957: 楼房重建 线段树

    2957: 楼房重建 Time Limit: 10 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 小A的楼房外有一大片施 ...

  3. bzoj 2957 楼房重建 分块

    楼房重建 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=29 ...

  4. [BZOJ 2957]楼房重建(THU2013集训)(线段树维护单调栈)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2957 分析: 根据题意,就是比较斜率大小 只看一段区间的话,那么这段区间能看见的楼房数量就是这 ...

  5. BZOJ 2957 楼房重建 (线段树)

    题目链接  楼房重建 解题思路:我们可以把楼房的最高点的斜率计算出来.那么问题就转化成了实时查询x的个数,满足数列x的左边没有大于等于x的数. 我们可以用线段树维护 设t[i]为如果只看这个区间,可以 ...

  6. 洛谷 P4198 BZOJ 2957 楼房重建

    题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个 ...

  7. BZOJ 2957 楼房重建

    Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...

  8. bzoj 2957 楼房重建 (线段树+思路)

    链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2957 思路: 用分块可以很简单的过掉,但是这道题也可以用线段树写. 分类讨论左区间最大值对 ...

  9. bzoj 2957: 楼房重建 ——线段树

    Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...

随机推荐

  1. ruby 数据类型Symbol

    一.符号创建 符号是Symbol类的实例,使用冒号加一个标识符即可创建符号 :a :"This is a symno" 二.符号字符串相互转换 p :symbol.to_s #=& ...

  2. TopCoder SRM 489 Div1 Lev3:AppleTree

    挺优秀的一道题,想出做法时有些惊艳. 题意: 数轴上有\(D\)个连续整数刻度,有\(N\)棵树要种在这些刻度上,其中第\(i\)棵与两旁(如果有的话)相邻的树至少要相距\(R_i\),问方法数. \ ...

  3. ABAP CDS ON HANA-(12)ODATA Service

    Create a CDS view and we have the view type as ‘BASIC’ view To publish this as oData, add the annota ...

  4. ChipScope软件使用

    内容组织 1.建立工程  2.插入及配置核  2.1运行Synthesize  2.2新建cdc文件  2.3 ILA核的配置  3. Implement and generate programmi ...

  5. C语言 字符数组与字符指针比较

    C语言 字符数组与字符指针比较 #include<stdio.h> /* 字符数组会在定以后预先分配内存空间字符串是常量所以会直接把字符串拷贝到数组中, 因为数组地址不同,所以不相等· 字 ...

  6. 20145202马超 实验二《Java面向对象程序设计》实验报告

    实验二 Java面向对象程序设计 实验内容 1.初步掌握单元测试和TDD 2.理解并掌握面向对象三要素:封装.继承.多态 3.初步掌握UML建模 4.熟悉S.O.L.I.D原则 5.了解设计模式 实验 ...

  7. 【C#】 语法糖

    [C#] 语法糖 一, 扩展方法 1. 对某个类功能上的扩展 2. 特点: 使用方便,可以在不修改原代码的基础上进行扩展. 参照 linq,linq 就是一系列的扩展方法 3. 语法: 非泛型静态类, ...

  8. 一个知乎日报pwa

    前几天写了一篇文章关于如何实现一个简单版的pwa应用,端午撸了一个简易版知乎日报pwa. 关于如何写一个pwa,这里就不多介绍了,请移步这里.应用使用vue+vuex+axios,API这里,这里做了 ...

  9. 「暑期训练」「基础DP」FATE(HDU-2159)

    题意与分析 学习本题的时候遇到了一定的困难.看了题解才知道这是二重背包.本题的实质是二重完全背包.二维费用的背包问题是指:对于每件物品,具有两种不同的费用,选择这件物品必须同时付出这两种代价:对于每种 ...

  10. Spotlight on MySQL

    聚光灯在MySQL 1.Sessios会话Total Users:总用户数前连接到MySQL服务器的用户会话总数Active Users:活跃用户此控件表示连接到当前正在执行SQL语句或其他数据库请求 ...