CodeForces #539 div1 C. Sasha and a Patient Friend【线段树】

题目描述:

在这里插入图片描述

题目分析:

把时间看做线段上的一个个格子组成,每个格子的水量变化由格子开始的水速决定。
水速是很容易用线段树维护的,所以区间[l,r]的水量变化就可以维护。
询问就只需要在线段树上二分就行了。
具体的,线段树节点的成员是这样的(注意时间范围很大,而下面的代码并没有离散化所以是动态开点的):

struct node{
	int ch[2],v;//左右儿子,区间起始点的水速(只有l==r||cov==1有意义)
	bool cov;//是否被覆盖
	LL sum,lsum;//总流量,前缀最小流量 
}t[maxn*40];

改变一个时刻的水速以及删除操作用map可以很方便的得出修改区间(感叹STL的强大,详见代码)

Code:

#include<bits/stdc++.h>
#define maxn 100005
#define x first
#define y second
#define LL long long
using namespace std;
struct node{
	int ch[2],v;
	bool cov;
	LL sum,lsum;//总流量,前缀最小流量 
}t[maxn*40];
#define lc t[i].ch[0]
#define rc t[i].ch[1]
int Q,root,sz;
void upd(int i){
	if(!lc) lc=++sz;
	if(!rc) rc=++sz;
	t[i].sum=t[lc].sum+t[rc].sum;
	t[i].lsum=min(t[lc].lsum,t[lc].sum+t[rc].lsum);
}
void cover(int &i,int l,int r,int v){
	if(!i) i=++sz;
	t[i].cov=1,t[i].v=v;
	t[i].sum=1ll*(r-l+1)*v;
	t[i].lsum=(v>=0?0:t[i].sum);	
}
void pushdown(int i,int l,int mid,int r){
	if(t[i].cov){
		cover(lc,l,mid,t[i].v);
		cover(rc,mid+1,r,t[i].v);
		t[i].cov=0; 
	} 
}
void insert(int &i,int l,int r,int x,int y,int v){
	if(!i) i=++sz;
	if(x<=l&&r<=y) {cover(i,l,r,v);return;}
	int mid=(l+r)>>1;
	pushdown(i,l,mid,r);
	if(x<=mid) insert(lc,l,mid,x,y,v);
	if(y>mid) insert(rc,mid+1,r,x,y,v);
	upd(i);
}
typedef pair<double,LL> pdl;
pdl query(int &i,int l,int r,int x,int y,LL s){
	if(!i) i=++sz;
	if(x<=l&&r<=y){
		if(s+t[i].lsum>0) return make_pair(-1,t[i].sum);
		if(l==r||t[i].cov) return make_pair(l-1.0*s/t[i].v,t[i].sum); 
	}
	int mid=(l+r)>>1;
	pushdown(i,l,mid,r);
	if(y<=mid) return query(lc,l,mid,x,y,s);
	if(x>mid) return query(rc,mid+1,r,x,y,s);
	pdl lret = query(lc,l,mid,x,y,s);
	if(lret.x>0) return lret;
	pdl rret = query(rc,mid+1,r,x,y,s+lret.y);
	return make_pair(rret.x,lret.y+rret.y);
}
const int N = 1e9;
map<int,int>T; 
int main()
{
	scanf("%d",&Q);
	T[0]=T[N+1]=0;
	int op,l,r,v;
	while(Q--){
		scanf("%d%d",&op,&l);
		if(op==1){
			scanf("%d",&v); T[l]=v;
			auto it = T.find(l); it++;
			insert(root,1,N,l,it->x-1,v);
		}
		else if(op==2){
			auto it = T.find(l), pre = it, nxt = it;
			pre--, nxt++; T.erase(it);
			insert(root,1,N,l,nxt->x-1,pre->y);
		}
		else{
			scanf("%d%d",&r,&v);
			if(!v) printf("%d\n",l);
			else if((l=T.lower_bound(l)->x)>=r) puts("-1");
			else{
				auto ans = query(root,1,N,l,r-1,v);
				if(ans.x<0) puts("-1");
				else printf("%.10f\n",ans.x);
			}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值