这个题题意我大概解释一下,就是一开始一条直线,上面的点全是联通的,有三种操作

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 线段树的合并的更多相关文章

  1. HDU 3911 线段树区间合并、异或取反操作

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911 线段树区间合并的题目,解释一下代码中声明数组的作用: m1是区间内连续1的最长长度,m0是区间内连续 ...

  2. hdu 3308(线段树区间合并)

    LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  3. HDU 3911 线段树区间合并

    北京赛区快了,准备袭击数据结构和图论.倒计时 18天,线段树区间合并.维护一个最长连续.. 题意:给一个01串,以下有一些操作,问区间最长的连续的1的个数 思路:非常裸的线段树区间合并 #includ ...

  4. hdu 1540 线段树

    这题的意思是现在有一些村庄成一条直线排列,现在有三个操作,D:摧毁一个指定的村庄,Q:询问与指定村庄相连的村庄个数, 就是这个村庄向左和向右数村庄数量,遇到尽头或损坏的村庄为止,这个就是与这个村庄相连 ...

  5. HDU 1540<线段树,区间并>

    题目连接 参考 题意: 维护各个点的连续的最大连续长度. 思路: 主要是维护一个区间的三个变量ll,f[i].l为起点向右的最大连续 长度,rl:f[i].r为起点向左的最大连续长度,ml:[l,r] ...

  6. I - Tunnel Warfare HDU - 1540 线段树最大连续区间

    题意  :一段区间  操作1 切断点 操作2 恢复最近切断的一个点 操作3 单点查询该点所在最大连续区间 思路:  主要是push_up :  设区间x 为母区间  x<<1 ,x< ...

  7. hdu 1806(线段树区间合并)

    Frequent values Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  8. hdu 3308 线段树 区间合并+单点更新+区间查询

    LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  9. HDU 3308 LCIS (线段树区间合并)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[ ...

随机推荐

  1. Win10 - MySQL-zip安装方法

    Win10 - MySQL-zip安装方法 安装步骤 1.下载,到MySQL官网:https://dev.mysql.com/downloads/mysql/ 2.解压安装包 解压下载的安装包,放到你 ...

  2. ASP.NET -- WebForm -- 缓存Cache的使用

    ASP.NET -- WebForm --  缓存Cache的使用 把数据从数据库或文件中读取出来,放在内存中,后面的用户直接从内存中取数据,速度快.适用于经常被查询.但不经常变动的数据. 1. Te ...

  3. May 26. 2018 Week 21st Saturday

    Do what you say, say what you do. 做你说过的,说你能做的. Be honest to yourself, and be honest to those people ...

  4. Unity Shader 效果(1) :图片流光效果

    很多游戏Logo中可以看到这种流光效果,一般的实现方案就是对带有光条的图片uv根据时间进行移动,然后和原图就行叠加实现,不过实现过程中稍稍有点需要注意的地方.之前考虑过风宇冲的实现方式,但是考虑到sh ...

  5. [福大软工] Z班 团队Beta阶段成绩汇总

    Beta敏捷冲刺得分 队伍名 1 2 3 4 5 总分 Dipper 10 10 10 10 10 50 SWSD 9 9 9 9 7 43 五成胜算 10 10 10 10 10 50 人月神教 0 ...

  6. 新近碰到的病毒(TR.Spy.Babonock.A)

    先来段Microsoft的说明: Worm:Win32/Babonock.A Alert level: Severe Detected with Windows Defender Antivirus ...

  7. c# 行转列动态赋值给layui

    数据库存储格式 期望前端显示样式 以下是代码: (1)控制器: [HttpGet("SocialImportLedgerInfo")] public ResultData GetS ...

  8. 如何征服面试官,拿到Offer [转]

    转自 https://my.oschina.net/cccyb/blog/3012768 又到了茶余饭后的时间,想想写点什么,掐指一算,噢呦,快到3月份了,职场的金三银四跳槽季又来了,不同的是今年比往 ...

  9. Android-SpinKit 进度条 (ProgressBar)

    项目地址: https://github.com/ybq/Android-SpinKit 类别: 进度条 (ProgressBar) 打分: ★★★★★ 更新: 2016-03-28 11:17 大小 ...

  10. Arduino 操作OLED

    https://item.taobao.com/item.htm?_u=n1qf7bf5beef&id=562158712128 1.模块尺寸:35(L)*31(W)mm 2.电源电压:2.8 ...