【题解】Siano [PA2015] [Bzoj4293] / Chika 的烦恼
传送门:( ext{Siano [PA2015]}) ( ext{[Bzoj4293]}) ( ext{ / Chika 的烦恼})
【分析】
看完题目第一感觉是超哥线段树,但仔细一想发现了个奇妙的性质:由于每次割草只会砍掉最高的那部分,所以生长速度快的草永远都不会比速度慢的矮(顶多一样高)。
可以对速度排个序,那么每次操作的部分一定是一个连续的区间,上线段树即可。
每个区间维护高度和 (S)、高度覆盖标记 (tag)、时间增量标记 (add) 、区间最大高度 (AR)(即最右边的草的高度),对于一次操作 (x_i,y_i) 在线段树上二分找到第一个大于等于 (x_i) 的位置 (pos),然后将 ([pos,n]) 全部覆盖为 (y_i),顺便在覆盖的同时计算改变量即为答案。
注意一些实现上的细节:
(pushdown) 时优先下放覆盖标记。
区间被覆盖后要清空 (add) 。
有可能找不到大于等于 (x_i) 的位置(全部都小于 (x_i)),这时要特判。
开 ( ext{long long}) 。
【Code】
#include<algorithm>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=5e5+3;
int n,T,V[N];LL x,y,SV[N];
template<typename T>inline void in(T &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
struct Sakura2{
struct Segment_Tree{
#define pl (p<<1)
#define pr (p<<1|1)
#define mid ((L+R)>>1)
struct QAQ{LL S,AR,add,tag;}tr[N<<2];
inline void build(Re p,Re L,Re R){
tr[p].tag=-1;
if(L==R)return;
build(pl,L,mid),build(pr,mid+1,R);
}
inline void pushup(Re p){
tr[p].S=tr[pl].S+tr[pr].S,tr[p].AR=tr[pr].AR;
}
inline void updata1(Re p,Re L,Re R,LL v){
tr[p].tag=v,tr[p].S=(LL)(R-L+1)*v,tr[p].AR=v,tr[p].add=0;
}
inline void updata2(Re p,Re L,Re R,LL v){
tr[p].add+=v,tr[p].S+=(LL)(SV[R]-SV[L-1])*v,tr[p].AR+=(LL)V[R]*v;
}
inline void pushdown(Re p,Re L,Re R){
if(tr[p].tag!=-1)updata1(pl,L,mid,tr[p].tag),updata1(pr,mid+1,R,tr[p].tag),tr[p].tag=-1;
if(tr[p].add)updata2(pl,L,mid,tr[p].add),updata2(pr,mid+1,R,tr[p].add),tr[p].add=0;
}
inline int find(Re p,Re L,Re R,LL v){
if(L==R)return tr[p].S<v?n+1:L;
pushdown(p,L,R);
if(tr[pl].AR>=v)return find(pl,L,mid,v);
else return find(pr,mid+1,R,v);
}
inline LL change(Re p,Re L,Re R,Re l,Re r,LL v){
if(l>r)return 0;
if(l<=L&&R<=r){LL tmp=tr[p].S;updata1(p,L,R,v);return tmp-tr[p].S;}
LL ans=0;pushdown(p,L,R);
if(l<=mid)ans+=change(pl,L,mid,l,r,v);
if(r>mid)ans+=change(pr,mid+1,R,l,r,v);
pushup(p);return ans;
}
}TR;
inline void sakura(){
sort(V+1,V+n+1);
for(Re i=1;i<=n;++i)SV[i]=SV[i-1]+V[i];
LL nowT=0;TR.build(1,1,n);
while(T--){
in(x),in(y),TR.updata2(1,1,n,x-nowT),nowT=x;
printf("%lld
",TR.change(1,1,n,TR.find(1,1,n,y),n,y));
}
}
}T2;
int main(){
// freopen("grass.in","r",stdin);
// freopen("grass.out","w",stdout);
in(n),in(T);
for(Re i=1;i<=n;++i)in(V[i]);
T2.sakura();
}