Codeforces 948C Producing Snow【二分,线段树】

题意:

爱丽丝每天会堆一堆雪体积为 Vi,每天的温度是Ti,每天还存在的雪堆就会融化 Ti 的体积,问每天融化雪体积的总量是多少。

思路:

可以将温度维护一个前缀和,对于每个雪堆每次就可以二分查找到这个雪堆完全融化是在第几天,假如第 i 天的雪堆二分查找到是在第 j 天融化完,那么就可以对  [ i , j ) 这个区间都加1 (使用线段树维护)意味着融化了一个完整的 Ti ,第 j 天融化的雪量单独记下来,最后查找融化了多少。

代码:

#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
const int max_n=100100;
typedef long long Lint;

Lint a[max_n];
struct Node{
	Lint sum;
	Lint add;
	int ls;
	int rs;
}tree[max_n<<2];

void Build(int num,int l,int r){
	tree[num].ls=l;
	tree[num].rs=r;
	tree[num].add=0;
	if(l==r){
		tree[num].sum=a[l];
		return;
	}
	int mid=(l+r)/2;
	Build(num<<1,l,mid);
	Build(num<<1|1,mid+1,r);
	tree[num].sum=tree[num<<1].sum+tree[num<<1|1].sum;
	return;
}

void pushdown(int num,int ls,int rs){
	if(tree[num].add!=0){
		tree[ls].sum+=tree[num].add*(tree[ls].rs-tree[ls].ls+1);
		tree[rs].sum+=tree[num].add*(tree[rs].rs-tree[rs].ls+1);
		tree[ls].add+=tree[num].add;
		tree[rs].add+=tree[num].add;
		tree[num].add=0;
	}
}

void Update(int num,int l,int r,int fl,int fr,int val){
	if(fl>r || fr<l)  return;
	if(fl<=l && r<=fr){
		tree[num].sum+=(tree[num].rs-tree[num].ls+1)*val;
		tree[num].add+=val;
		return;
	}
	//if(l==r) return;
	pushdown(num,num<<1,num<<1|1);
	int mid=(l+r)>>1;
	Update(num<<1,l,mid,fl,fr,val);
	Update(num<<1|1,mid+1,r,fl,fr,val);
	tree[num].sum=tree[num<<1].sum+tree[num<<1|1].sum;
	return ;
}

Lint Query(int num,int l,int r,int fl,int fr){
	if(fl>r || fr<l) return 0;
	if(fl<=l && r<=fr) return tree[num].sum;
	pushdown(num,num<<1,num<<1|1);
	int mid=(l+r)/2;
	Lint res1=Query(num<<1,l,mid,fl,fr);
	Lint res2=Query(num<<1|1,mid+1,r,fl,fr);
	return res1+res2;
}
以上为线段树区间更新模板
Lint vv[max_n];
Lint tt[max_n];
Lint res[max_n];
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%lld",&vv[i]);
    }
    for(int i=1;i<=n;i++){
        scanf("%lld",&tt[i]);
        tt[i]+=tt[i-1];
    }
    for(int i=1;i<=n;i++){
        int index=lower_bound(tt+i,tt+n+1,tt[i-1]+vv[i])-(tt);
        int l,r;
      //  cout<<"index=="<<index<<endl;
        res[index]+=vv[i]-(tt[index-1]-tt[i-1]);
        l=i; r=index-1;
        if(l<=r){
            Update(1,1,n,l,r,1);
        }
    }
    for(int i=1;i<=n;i++){
        res[i]+=Query(1,1,n,i,i)*(tt[i]-tt[i-1]);
    }
    for(int i=1;i<=n;i++){
        printf("%lld%c",res[i],i==n?'\n':' ');
    } 
}

int main(){
	solve();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值