蜂蜜柚子茶
作者:互联网
题目描述
是从什么时候开始的呢···
大概是在「沽酒」的那一晚,小戾不声不响地给他们包厢上了多放了很多糖的蜂蜜柚子茶。
在自己被灌了不少酒之时,给向来嗜甜的自己。
小戾的面前放了\(N\)杯正常甜度的蜂蜜柚子茶,茶底都是早就做好的,是精心调配的比例。先前并没有往里添加糖的先例。
不过如果是给LCT的话,又有何不可。
小戾的「沽酒」设备先进,有批量给多杯饮品加糖的机器。说是加糖,其实就是撒糖。小戾在吧台上将N杯饮品排成一排,每次操作会以一个点为中心,在一个半径内给一些饮料添加糖。使用这种方式,总是位于中心的饮料被加的糖最多,而随着与中心的距离越来越远,饮品中被撒入的糖逐渐减少。具体来说,一次撒糖可以用三个参数来描述:\(x_i,r_i,w_i\),其中
\(x_i\):表示撒糖的中心。
\(r_i\):表示撒糖的半径。对于\(1≤j≤n\)的所有\(j\),当\(|j−x_i|≤r_i\)时,第\(j\)杯饮品中就会被撒入糖。注意,这并不代表\(x−r_i∈[1,n]\),机器撒糖当然有可能会将糖撒到杯子外面,我们不需要考虑这些撒出边界的糖。也就是说,当一杯饮品与撒糖中心之间的距离不超过撒糖半径ri时,这杯饮品就会被撒入糖。
wi:用于量化被撒到的糖。对于在该次撒糖半径中的饮品\(j\),即满足\(|j−x_i|≤r_i\)的某个\(j\),在该次撒糖过程中将会被撒到\(w_i−|j−x_i|\)单位的糖。也就是说,撒糖中心会被撒到wi单位的糖,每往左/右移一位,撒的糖数量就会减少一个单位。当然,被撒到糖的前提是位于撒糖半径内,在撒糖半径之外的饮品被撒入糖的量都是0。
小戾在撒的过程中也会做一些抽样,比如指定某一杯饮品,问它目前添加的糖有多少。
注意,初始时所有饮品都为正常糖量,可被认为是0单位添加糖。
输入格式
第一行两个数\(N,M\)。分别表示饮品的数量和操作的个数。
接下来M行,每行格式为下面的某一种:
+ \(x_i r_i w_i\):表示以xi为撒糖中心,\(r_i\)为撒糖半径,\(w_i\)为撒糖中心被撒到的糖量进行一次撒糖操作。
? \(x_i\):表示询问第\(x_i\)杯饮品的甜度。
保证\(1≤x_i,r_i≤n,0≤w_i≤10^9\)。保证\(r_i≤w_i\),即撒糖操作「撒」的糖必然是非负整数,不会「抽」糖。
输出格式
对于每个?输出一行表示答案。
样例输入1
3 5
+ 2 3 4
+ 1 1 2
+ 3 1 2
? 1
+ 1 2 8
样例输出1
5
样例输入2
10 5
+ 9 9 7
? 7
? 4
? 9
? 10
样例输出2
5
2
7
6
题目限制
时间限制:1000ms
空间限制:512MB
对于30%的数据,\(N,M≤10^3\)。
另有20%的数据,满足\(w_i≤10^4\)。
对于100%的数据,满足\(N,M≤2×10^5\)。 保证\(1≤x_i,r_i≤n,0≤w_i≤10^9,r_i≤w_i\)。
这道题其实第二个样例不符合题目要求,没过的可以尝试
区间加,单点求和,尝试用线段树解决。
首先如果区间加的是一个等差数列,其实也能用线段树做,但是太麻烦了,我们考虑用一些简单的方法解决。
对原数列进行差分后,我们可以发现,在某一段区间差分序列增加了1,后面又减少了1.
先通过半径求出撒糖的区间\(l\)和1\(r\),然后发现\(l+1\sim x\)的差分序列加了1,\(x+1\sim r\)这一段减少了1,同时按照题目给的公式求出\(l\)和\(r\)的增量\(x\)和\(y\),然后在l处差分序列增加\(x\),\(r+1\)处减少了y。
注意处理边界问题(n=1),询问x时输出\(1\sim x\)的和即可。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,x,y,w,l,r;
char op;
struct node{
long long sum,tag;
}tr[N<<2];
void pushdown(int o,int l,int r)
{
int md=l+r>>1;
tr[o<<1].tag+=tr[o].tag;
tr[o<<1|1].tag+=tr[o].tag;
tr[o<<1].sum+=tr[o].tag*(md-l+1);
tr[o<<1|1].sum+=tr[o].tag*(r-md);
tr[o].tag=0;
}
void update(int o,int l,int r,int x,int y,int z)
{
if(x<=l&&r<=y)
{
tr[o].sum+=1LL*(r-l+1)*z;
tr[o].tag+=z;
return;
}
pushdown(o,l,r);
int md=l+r>>1;
if(md>=x)
update(o<<1,l,md,x,y,z);
if(md<y)
update(o<<1|1,md+1,r,x,y,z);
tr[o].sum=tr[o<<1].sum+tr[o<<1|1].sum;
}
long long query(int o,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
return tr[o].sum;
pushdown(o,l,r);
int md=l+r>>1;
long long ret=0;
if(md>=x)
ret+=query(o<<1,l,md,x,y);
if(md<y)
ret+=query(o<<1|1,md+1,r,x,y);
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf(" %c",&op);
if(op=='?')
{
scanf("%d",&x);
printf("%lld\n",query(1,1,n,1,x));
}
else
{
scanf("%d%d%d",&x,&y,&w);
l=max(x-y,1),r=min(x+y,n);
if(l!=r)
{
update(1,1,n,l,l,w-x+l);
if(r<n)
update(1,1,n,r+1,r+1,r-x-w);
if(l<x)
update(1,1,n,l+1,x,1);
if(x<r)
update(1,1,n,x+1,r,-1);
}
else
update(1,1,n,x,x,w);
}
}
return 0;
}
标签:10,撒糖,小戾,饮品,样例,柚子茶,半径,蜂蜜 来源: https://www.cnblogs.com/mekoszc/p/16270854.html