题目链接:点击查看

题目大意:给出n个线段代表集合,现在问若可以将其中任意一个线段删除,则能够形成最多多少个独立的集合(取并集后)

题目分析:看到区间不难想到线段树了,虽然这个题也可以用stl贪心做,但需要考虑的因素太多了,还是用线段树直接莽吧,虽然前期的理论已经准备的很充分了,但在中途写线段树的时候还是写崩了,最开始的那个线段树没有想太多,直接更新到叶子结点,TLE,加个lazy优化一下吧,但优化的不到位,TLE,最后还是参考了zx学长的代码,豁然开朗,想明白了对于这个题目的几个关键的点,冲着这几个点改了一下线段树的内部实现,然后就A了

上面说的是这个题的心路历程,回到这个题目来,最直接的想法就是用线段树维护一个cover变量,表示每个区间被覆盖的次数,再单独维护一个sum变量,用来表示区间内有多少个独立的集合,也就是不接壤的线段,最后就是维护一个布尔类型的ll和rr,分别表示左端点和右端点是否被覆盖,在区间合并的时候要用到

具体该如何使用上面的变量呢,首先将n个线段读入到线段树中,此后以此枚举每个线段删除之后的答案,根据上面变量的定义,显然答案就是tree[1].sum,所以对于更新来说我们只需要让当前枚举的线段的cover减一即可,最后别忘了回溯,时间复杂度是nlogn级别的,带点常数无伤大雅

这个题的关键就是区间的范围给的太大了,有2e9那么多,只能离散化,但面临的一个问题是,离散化后只剩下了端点的情况,端点内部的区间都被离散化掉了,但在这个题目中我们是需要用到的,所以在离散化的时候将区间内、区间左、区间右这三个位置顺便一起离散化一下就可以了,相当于将区间内的所有空白点压缩成了一个点,具体实现就是让端点都乘以二,这样既能解决题目中相邻区间不相交的问题,如[1,4][5,6]就属于两个集合,而不是一个集合,也能解决上述离散化的问题,一举两得

讲完离散化后我们就可以直接写线段树了,具体实现还是看代码吧,打上注释了都,只可意会不可言谈

最后说一下这个题的几个关键点吧,因为我们最终需要的是tree[1].sum,换句话说,只有涉及到最终答案的值才需要更新一下,假如某个区间已经被更新了,那么其接下来的子树就无需遍历了,因为知道了当前区间的状态,就足以向上维护最终答案了,而对于lazy变量,在这个题目中实际上就是cover变量,因为这个题目无需向下传递任何信息,只需要向上传递信息用来维护最终答案,所以在这个题目中的cover变量的用途具体也是用来维护状态的

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2e5+100;struct Node
{int l,r,sum,cover;//sum:有多少个区间段 cover:被覆盖了几次 bool ll,rr;//左右端点是否被覆盖
}tree[N<<5]; void pushup(int k)
{if(tree[k].cover)//如果当前区间被覆盖,直接更新数据 {tree[k].sum=1;tree[k].ll=tree[k].rr=true;}else//如果没被覆盖,则用子节点更新 {tree[k].ll=tree[k<<1].ll;tree[k].rr=tree[k<<1|1].rr;tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;if(tree[k<<1].rr&&tree[k<<1|1].ll)//如果左子树的右端点和右子树的左端点同时被覆盖,则区间段减一,有点区间合并的意思 tree[k].sum--;}
}void init(int k,int l,int r)
{tree[k].ll=tree[k].rr=false;tree[k].l=l;tree[k].r=r;tree[k].sum=tree[k].cover=0;
}void build(int k,int l,int r)
{init(k,l,r);if(l==r)//叶子结点需要特别更新一下其子节点,因为下面update函数在叶子结点时可能直接调用pushup,若没有初始化则会因为之前的数据没有初始化而出错{init(k<<1,l,r);init(k<<1|1,l,r);return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}void update(int k,int l,int r,int val)
{if(l>tree[k].r||r<tree[k].l)return;if(tree[k].l>=l&&tree[k].r<=r){tree[k].cover+=val;pushup(k);return;}int mid=tree[k].l+tree[k].r>>1;update(k<<1,l,r,val);update(k<<1|1,l,r,val);pushup(k);//记得上传状态
}vector<int>v;//离散化用 int get_id(int x)
{return lower_bound(v.begin(),v.end(),x)-v.begin();
}void dis_create()
{v.push_back(-inf);sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());
}struct Section
{int l,r;void input()//记得除了左右端点还需要加上一些空端点,不然不好判断区间段的连续性 {scanf("%d%d",&l,&r);v.push_back(2*l);v.push_back(2*r);v.push_back(2*l-1);v.push_back(2*r+1);v.push_back(2*l+1);}void dis_create()//更新离散化后的id {l=get_id(2*l);r=get_id(2*r);}
}a[N];int main()
{
//  freopen("input.txt","r",stdin);int w;cin>>w;while(w--){v.clear();int n;scanf("%d",&n);for(int i=1;i<=n;i++)a[i].input();dis_create();for(int i=1;i<=n;i++)//将区间端点离散化 a[i].dis_create();build(1,1,v.size());for(int i=1;i<=n;i++)update(1,a[i].l,a[i].r,1);int ans=0;for(int i=1;i<=n;i++){update(1,a[i].l,a[i].r,-1);ans=max(ans,tree[1].sum);update(1,a[i].l,a[i].r,1);}printf("%d\n",ans);}return 0;
}

CodeForces - 1285E Delete a Segmen(线段树+区间合并+离散化)相关推荐

  1. CodeForces - 1539F Strange Array(线段树区间合并)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的序列,规定位置 iii 的贡献是:设 x=a[i]x=a[i]x=a[i],选择一个包含 iii 的区间 [l,r][l,r][l,r],将其中 ...

  2. Codeforces 444C DZY Loves Colors 线段树区间更新

    // Codeforces 444C DZY Loves Colors 线段树区间更新// 题目链接:// http://codeforces.com/problemset/problem/444/C ...

  3. 树链剖分——线段树区间合并bzoj染色

    线段树区间合并就挺麻烦了,再套个树链就更加鬼畜,不过除了代码量大就没什么其他的了.. 一些细节:线段树每个结点用结构体保存,pushup等合并函数改成返回一个结构体,这样好写一些 struct Seg ...

  4. SPOJ GSS3-Can you answer these queries III-分治+线段树区间合并

    Can you answer these queries III SPOJ - GSS3 这道题和洛谷的小白逛公园一样的题目. 传送门: 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间 ...

  5. Tunnel Warfare(HDU1540+线段树+区间合并)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540 题目: 题意:总共有n个村庄,有q次操作,每次操作分为摧毁一座村庄,修复一座村庄,和查询与询问的 ...

  6. 牛客 - 求函数(线段树+区间合并/线段树+矩阵维护)

    题目链接:点击查看 题目大意:现在有 n 个函数,每个函数都是诸如 f( x ) = k * x + b 的形式,只是每个函数的 k 和 b 都是相互独立的,现在给出两个操作: 1 pos k b:将 ...

  7. 2021牛客暑期多校训练营7 xay loves monotonicity 线段树区间合并

    传送门 文章目录 题意: 思路: 题意: 题面挺绕口的,还是看原题比较好. 大概的意思就是让你从给定的区间中选择一个以左端点为起点的一个上升子序列,让后将这些下标存下来,在bbb中将这些位置拿出来后, ...

  8. poj-3667(线段树区间合并)

    题目链接:传送门 参考文章:传送门 思路:线段树区间合并问题,每次查询到满足线段树的区间最左值,然后更新线段树. #include<iostream> #include<cstdio ...

  9. HDU3308 线段树区间合并

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 ,简单的线段树区间合并. 线段树的区间合并:一般是要求求最长连续区间,在PushUp()函数中实 ...

最新文章

  1. 【Sql Server】DateBase-触发器
  2. Android Handler 流程解析
  3. 比特币这么火热,看看这篇比特币初学者指南
  4. eclipse中svn和TortoiseSVN更改账号的方法
  5. java 调用动态链接库_JAVA技巧:JNative调用动态链接库问题(SOS)
  6. ES6新特性_Promise实践练习-多个文件内容读取---JavaScript_ECMAScript_ES6-ES11新特性工作笔记028
  7. 获取SQL Server数据库增长和收缩事件的详细信息
  8. ClickHouse表引擎Distributed介绍-尚硅谷大数据培训
  9. SELinux audit2allow命令使用
  10. Model based RL概述
  11. 数仓建模—国产建模工具神器
  12. 三线制接近开关原理及接线图
  13. 华为防火墙应用层过滤--URL
  14. 特征多项式及Cayley-Hamilton定理
  15. jdk eclipes 配置 MySql navicat8_mysql_en安装
  16. python图形用户界面page_Python+selenium使用PageObject实现UI自动化
  17. pandas合并文件夹下的excel文件
  18. 国产化替代加速升温,智和信通着力信创技术再迎突破
  19. 关于修改ant table选中行的背景色
  20. java cookie路径_路径问题以及cookie详解

热门文章

  1. outlook html阅读,Html Email 邮件html页编写指南
  2. 索引方式:真的是用的B+Tree 吗?
  3. MVC 顶层设计-HandlerMapping
  4. 基于Xml 的IOC 容器-载入<property>元素
  5. 委派模式与策略模式综合应用
  6. 分布式事务常见解决方案-关于状态机
  7. 单机环境RocketMQ的安装
  8. 函数式接口作为方法的返回值
  9. SpringMVC的数据响应-回写数据-直接回写json格式字符串(应用)
  10. hibernate-validate