HDU - 1540 线段树的合并
这个题题意我大概解释一下,就是一开始一条直线,上面的点全是联通的,有三种操作
1.操作D把从左往右第x个村庄摧毁,然后断开两边的联通。
2.询问Q节点相联通的最长长度
3.把最后破坏的村庄重建。
这个其实也是非常典型的线段树区间合并,正好可以学一下。
我们给线段树的结点赋予5个值,l 区间左端点, r 区间右端点, ls从左端点开始的最大连续个数(左连续),rs从右端点开始最大的连续个数,ms这个节点所表示的区间内部,最大的连续个数。
然后我们考虑建树,由于最开始是相通的,因此这些值初始为r-l+1
然后常规操作单点修改,现在考试如何维护的:
首先是左儿子节点的左连续传给父节点的左连续,右儿子的右连续传给父节点的右连续
然后是维护父节点的最大连续,父节点的最大连续有可能由三个部分得到:两个儿子节点的分离的最大连续,以及合并左儿子的右连续和右儿子的左连续。因此把这三个值的最大值拿出来即可。
然后考虑询问:
如果询问到叶节点,或者区间内部最大的连续区间为0(代表区间内全是0)或者区间值等于区间长度(区间满了)这些可以直接退出循环。
让后我们考虑询问分裂的时候的问题,如果我们询问的点在树的左边,我们会发现有两种情况:
如果这个点是大于在树的左儿子的右连续的左边界,意味着这个点联通着树的右节点,我们需要在询问左节点的同时,加上右节点的右连续,即t>=tree[L(root)].r-tree[L(root)].rs+1
否则我们只需要访问左节点,继续询问即可。
反之也是如此,从而实现了线段树的分裂和合并
#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int maxx = 1e5+;
int s[maxx];
inline int L(int r){return r<<;};
inline int R(int r){return r<<|;};
inline int MID(int l,int r){return (l+r)>>;};
struct node{
int l,r;
int ls,rs,ms;//左段开始最大连续区间,右端开始最大连续区间,节点区间内最大连续区间
}tree[maxx<<];
void buildtree(int root,int l,int r){
tree[root].l=l;
tree[root].r=r;
tree[root].ls=(r-l+);
tree[root].rs=(r-l+);
tree[root].ms=(r-l+);
if(l==r){
return;
}
int mid=MID(l,r);
buildtree(L(root),l,mid);
buildtree(R(root),mid+,r);
}
void update(int root,int t,int op){
int l=tree[root].l;
int r=tree[root].r;
if(l==r)//到叶节点
{
if (op==){//如果是销毁操作
tree[root].ls=tree[root].rs=tree[root].ms=;
}else{
tree[root].ls=tree[root].rs=tree[root].ms=;//恢复
}
return;
}
int mid=MID(l,r);
if (t<=mid){
update(L(root),t,op);
}else{
update(R(root),t,op);
}
tree[root].ls=tree[L(root)].ls;//把左儿子节点的左连续传给父亲节点
tree[root].rs=tree[R(root)].rs;//把右儿子节点的右连续传给父亲节点
tree[root].ms=max(max(tree[L(root)].ms,tree[R(root)].ms),tree[L(root)].rs+tree[R(root)].ls);
//父亲节点区间内的最大连续是由三部分构成,左右儿子的最大连续,以及左儿子的最大右连续加上右儿子的最大左连续
if (tree[L(root)].ls == tree[L(root)].r-tree[L(root)].l+)//如果左儿子区间满了,
tree[root].ls+=tree[R(root)].ls;//节点的左连续应该加上右儿子的左连续
if (tree[R(root)].rs == tree[R(root)].r-tree[R(root)].l+)//同理右儿子节点满了
tree[root].rs+=tree[L(root)].rs;//节点的右连续应该加上左儿子的右连续
}
int query(int root,int t)
{
int l=tree[root].l;
int r=tree[root].r;
if(l==r || tree[root].ms == || tree[root].ms==r-l+){
//到达一个叶子节点//或者里面全是呗摧毁的点//或者是区间已满的点
return tree[root].ms;
}
int mid=MID(l,r);
if (t<=mid)
{
if(t>=tree[L(root)].r-tree[L(root)].rs+)//t节点在看左子树,tree[2*i].r-tree[2*i].rs+1代表左子树右边连续区间的左边界值,如果t在左子树的右区间内,则要看右子树的左区间有多长并返回
return query(L(root),t)+query(R(root),mid+);
else
query(L(root),t);//如果不在左子树的右边界内,则只需要看左子树
}else
{
if (t<=tree[R(root)].l+tree[R(root)].ls-)//看右子树的左连续的右边界,如果t在在这个范围内,需要再次访问其从左儿子右边界开始的右连续从mid开始
return query(R(root),t)+query(L(root),mid);
else
return query(R(root),t);
}
}
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
buildtree(,,n);
char op;
int tmp;
int top;
while(m--){
scanf(" %c",&op);
if (op=='D'){
scanf("%d",&tmp);
s[top++]=tmp;
update(,tmp,);
}else if(op=='Q'){
scanf("%d",&tmp);
printf("%d\n",query(,tmp));
}else
{
if(tmp>)
{
tmp=s[--top];
update(,tmp,);
}
}
}
}
return ;
}
HDU - 1540 线段树的合并的更多相关文章
- HDU 3911 线段树区间合并、异或取反操作
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911 线段树区间合并的题目,解释一下代码中声明数组的作用: m1是区间内连续1的最长长度,m0是区间内连续 ...
- hdu 3308(线段树区间合并)
LCIS Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- HDU 3911 线段树区间合并
北京赛区快了,准备袭击数据结构和图论.倒计时 18天,线段树区间合并.维护一个最长连续.. 题意:给一个01串,以下有一些操作,问区间最长的连续的1的个数 思路:非常裸的线段树区间合并 #includ ...
- hdu 1540 线段树
这题的意思是现在有一些村庄成一条直线排列,现在有三个操作,D:摧毁一个指定的村庄,Q:询问与指定村庄相连的村庄个数, 就是这个村庄向左和向右数村庄数量,遇到尽头或损坏的村庄为止,这个就是与这个村庄相连 ...
- HDU 1540<线段树,区间并>
题目连接 参考 题意: 维护各个点的连续的最大连续长度. 思路: 主要是维护一个区间的三个变量ll,f[i].l为起点向右的最大连续 长度,rl:f[i].r为起点向左的最大连续长度,ml:[l,r] ...
- I - Tunnel Warfare HDU - 1540 线段树最大连续区间
题意 :一段区间 操作1 切断点 操作2 恢复最近切断的一个点 操作3 单点查询该点所在最大连续区间 思路: 主要是push_up : 设区间x 为母区间 x<<1 ,x< ...
- hdu 1806(线段树区间合并)
Frequent values Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- hdu 3308 线段树 区间合并+单点更新+区间查询
LCIS Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- HDU 3308 LCIS (线段树区间合并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[ ...
随机推荐
- OkHttp简单使用
OkHttp是一个轻量优秀的网络框架.用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient,) 使用方法: 1 ...
- python——函数之装饰器
1 问题 实际生活中,我们很难一次性就把一个函数代码写得完美无缺.当我们需要对以前的函数添加新功能时,我们应该怎么做? 2 问题解决思路 (1)可以直接修改原来的函数,在函数内直接修改.当我们对多个函 ...
- LeetCode算法题-Best Time to Buy and Sell Stock II
这是悦乐书的第173次更新,第175篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第32题(顺位题号是122).假设有一个数组,其中第i个元素是第i天给定股票的价格.设计 ...
- DbContext 和 ObjectContext两者的区别
ObjectContext是一种模型优先的开发模式,DbContext是代码优先的开发模式.这是两者最根本的区别. 同时两者之间可以相互转换: 下面给出转换的例子 1.DbContext转为Objec ...
- Linux /var/log下的各种日志文件详解
1)/var/log/secure:记录登录系统存取数据的文件;例如:pop3,ssh,telnet,ftp等都会记录在此. 2)/var/log/wtmp:记录登录这的信息记录,被编码过,所以必须以 ...
- 如何在linux平台上编译安装zlib软件(公司部分线上机器缺少zlib不能安装supervisor)
文章在Centos 6.5 linux平台上演示一下如何进行编译安装zlib软件,并配置相关的选项加载使用.示范从下载到安装并配置进行使用过程一系列整套讲解,希望可以给网友考虑使用,谢谢. 工具 ...
- 小程序request封装
我们知道,一个项目开发时,有许多环境,如:开发环境,测试环境,预生产环境,生成环境,若项目上线时要每个接口的域名改一遍,这是效率很低的做法.另外,许多接口都有前缀,例如 /api/ /wxapi/ ...
- WinForm下的loading框的实现
前言:在项目使用C/S模式情况下,由于需要经常进行数据的刷新,如果直接进行刷新,会有一个等待控件重画的过程,非常的不友好,因此在这里添加一个loading框进行等待显示. 实现:在经过多方面查询资料, ...
- postgresql + mybatis insert主键自增方法
postgresql + mybatis插入记录时设置自增主键方法: 一.数据库设置主键自增 1.数据库中id字段选择serial4类型后,会在默认值中生成 nextval('app_id_seq': ...
- vue 数据绑定实现的核心 Object.defineProperty()
vue深入响应式原理 现在是时候深入一下了!Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是普通的 JavaScript 对象.而当你修改它们时,视图会进行更新.这使得状态管理非常简 ...