【CF833E】Caramel Clouds(线段树)

题面

CF

洛谷

题解

首先把区间一段一段分出来,那么只有四种情况。

要么没有被任何一朵云被覆盖,那么直接就会产生这一段的贡献。

要么被一朵云覆盖,要么被两朵云覆盖。

要么被三朵及以上的云所覆盖,那么这段的贡献永远取不到。

对于每朵云预处理出只被其覆盖的区间长度\(len[i]\),这样子就能处理只选择一朵云的贡献了。

现在考虑如何处理选择两朵云。

这里有两种情况。

第一种是两朵云无交,那么贡献就是\(len[i]+len[j]\)。

否则的话有交,并且交的部分只被这两朵云所覆盖,不能发现这样子的情况不会超过\(n\)个,这个东西可以拿出来暴力更新。

这样子我们可以预处理一个前缀的值,代表在这个位置之前选择云能够得到的最大空出来的时间。

对于第一种情况,可以按照价格大小构建一棵线段树,这样子每次就是区间查最大值。

对于第二种情况,找到这个区间然后把两个的贡献算在一起就好了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define MAX 300300
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Cloud{int l,r,c;}c[MAX];
bool operator<(Cloud a,Cloud b){return a.c<b.c;}
struct Node{int t,opt,id;}a[MAX<<1];
bool operator<(Node a,Node b){return a.t<b.t;}
struct Qry{int k,id;}q[MAX];
bool operator<(Qry a,Qry b){return a.k<b.k;}
int n,m,C,cnt,ans[MAX],len[MAX],cho[MAX];
namespace SegmentTree
{
#define lson (now<<1)
#define rson (now<<1|1)
int t[MAX<<2];
void Modify(int now,int l,int r,int p,int w)
{
if(l==r){t[now]=w;return;}
int mid=(l+r)>>1;
if(p<=mid)Modify(lson,l,mid,p,w);
else Modify(rson,mid+1,r,p,w);
t[now]=max(t[lson],t[rson]);
}
int Getmax(int now,int l,int r)
{
if(l==r)return l;
int mid=(l+r)>>1;
if(t[lson]>t[rson])return Getmax(lson,l,mid);
else return Getmax(rson,mid+1,r);
}
int Query(int now,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return Getmax(now,l,r);
int mid=(l+r)>>1,ret=0;
if(L<=mid)ret=Query(lson,l,mid,L,R);
if(R>mid)
{
int x=Query(rson,mid+1,r,L,R);
if(len[x]>len[ret])ret=x;
}
return ret;
}
}
using namespace SegmentTree;
set<int> S;
map<int,int> M[MAX];
int Calc(int i,int j){if(i>j)swap(i,j);return len[i]+len[j]+M[i][j];}
int main()
{
n=read();C=read();
for(int i=1;i<=n;++i)c[i].l=read(),c[i].r=read(),c[i].c=read();
sort(&c[1],&c[n+1]);c[n+1]=(Cloud){0,0,2000000000};
for(int i=1;i<=n;++i)a[++cnt]=(Node){c[i].l,1,i},a[++cnt]=(Node){c[i].r,-1,i};
sort(&a[1],&a[cnt+1]);a[++cnt]=(Node){2000000010,1,n+1};
m=read();for(int i=1;i<=m;++i)q[i].k=read(),q[i].id=i;
sort(&q[1],&q[m+1]);
int Sum=0,Del=0;
for(int i=1,tim=0,pos=1;i<=cnt;++i)
{
int l=a[i].t-tim;tim=a[i].t;
if(!S.size())Sum+=l;
else if(S.size()==1)
{
int x=*S.begin();
len[x]+=l;cho[x]+=l;Modify(1,1,n,x,len[x]);
if(c[x].c<=C)
{
int l=1,r=upper_bound(&c[1],&c[n+1],(Cloud){0,0,C-c[x].c})-c-1,val=len[x];
if(l<=x&&x<=r)
{
if(l<=x-1)val=max(val,Calc(x,Query(1,1,n,l,x-1)));
if(x+1<=r)val=max(val,Calc(x,Query(1,1,n,x+1,r)));
}
else if(l<=r)val=max(val,Calc(x,Query(1,1,n,l,r)));
cho[x]=max(cho[x],val);
Del=max(Del,cho[x]);
}
}
else if(S.size()==2)
{
int x=*S.begin(),y=*S.rbegin();M[x][y]+=l;
if(c[x].c+c[y].c<=C)
{
cho[x]=max(cho[x],Calc(x,y));
cho[y]=max(cho[y],Calc(x,y));
Del=max(Del,max(cho[x],cho[y]));
}
}
while(pos<=m&&Del+Sum>=q[pos].k)ans[q[pos].id]=tim-(Del+Sum-q[pos].k),++pos;
if(a[i].opt==1)S.insert(a[i].id);
else S.erase(a[i].id);
}
for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
return 0;
}

【CF833E】Caramel Clouds(线段树)的更多相关文章

  1. CF833E Caramel Clouds

    题面 天上有$n$朵云,每朵云$i$会在时间$[l_i,r_i]$出现,你有$\text C$个糖果,你可以花费$c_i$个糖果让云$i$消失,同时需要保证你最多让两朵云消失.现在有$m$个独立的询问 ...

  2. 【CF833E】Caramel Clouds

    [CF833E]Caramel Clouds 题面 洛谷 题目大意: 天上有\(n\)朵云,每朵云\(i\)会在时间\([li,ri]\)出现,你有\(C\)个糖果,你可以花费\(c_i\)个糖果让云 ...

  3. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  4. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  5. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  6. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  7. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

  8. PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

  9. CF719E(线段树+矩阵快速幂)

    题意:给你一个数列a,a[i]表示斐波那契数列的下标为a[i],求区间对应斐波那契数列数字的和,还要求能够维护对区间内所有下标加d的操作 分析:线段树 线段树的每个节点表示(f[i],f[i-1])这 ...

随机推荐

  1. l^oo不可分的两个注意点

    1  不理解等一个等式 , 2.不理解为什么,一个可分的集合里面有不可数的子集?谢谢 1是 2.是可分集合里面每个元素 做中心后的一个开覆盖 所有0 1序列是和所有二进制小数   可以一一对应   而 ...

  2. openstack-KVM管理工具

    一. virsh 通过libvirt API管理Hpervisor.node.domain,实现多数功能调用. 即统一管理多台计算机上的域. 1.管理其他服务器(node) (1)修改配置文件:vim ...

  3. python模块详解

    什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的代码(.p ...

  4. Linux系统tree工具

    当用户在linux平台中需要需要查看一个非当前目录的目录下有哪些文件和子文件时,最普通的办法就是cd该目录,然后再ls,这个操作令人不舒适,因为查看完以后,用户还需要切换到原来的目录.现在介绍一款非常 ...

  5. Satis搭建composer私有库(自定义下载目录)

    在我们的日常php开发中需要使用大量的第三方包和类库, 怎么管理是一个问题, 我们用的Yii2框架, 但是并没有把composer用起来, 由于最近更换为docker部署项目, 于是想起来用compo ...

  6. C#复习笔记(1)--C#开发的进化史

    前言:陆续使用C#已经有一年半的时间.中间做过一些应用,现在为了有更高的提升,决定重新看一遍C# in depth,并总结一些笔记. 一.从简单的数据类型开始 上面是C#1到C#4中的一部分演变历程. ...

  7. Html5使用canvas作图线宽很粗

    自己使用canvas画图是碰到的问题,在这里记录一下.我把lineWidth设置为1,但是很粗,而且发虚.代码如下: <script type="text/javascript&quo ...

  8. [转帖] 百度知道: KMS 和OSPP

    https://zhidao.baidu.com/question/1819332749671662308.html Key Management Service (KMS).目前Windows Se ...

  9. Day 5-2 类的继承和派生,重用

    类的继承 派生 在子类中重用父类 组合 抽象类 定义: 继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创建新类的方式,在python中,新 ...

  10. C# Note8: 设计模式全解

    前言——资源说明 目前网上设计模式的介绍可谓非常之多(各种编程语言的版本),其中不乏精细之作,本文的目的在于搜集和整理C#或C++的设计模式,毕竟思想还是共通的! 设计模式的分类 创建型模式,共五种: ...