先不考虑清空,类似于一道叫siano的线段树题,我们把所有点按照加满的时间排序,然后某一个时刻满能量的就一定是一个后缀,然后就可以用线段树维护了
对于这道题,我们再用一个set维护一下删除时间相同的一段,每次查询就删除之前的并插入当前的,查询sum可以用主席树,分别维护前缀和后缀(满和未满),就是类似siano的方法
Code:
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=2e5+5;
int n;
ll v[N],m[N],s[N],t[N];
namespace President_tree{
int rt[N],cnt=0;
struct seg{int l,r;ll sum1,sum2;}tr[N*40];
#define ls(k) tr[k].l
#define rs(k) tr[k].r
void ins(int &rt1,int rt2,int l,int r,int pos,int id){
rt1=++cnt;
tr[rt1]=tr[rt2];
tr[rt1].sum1+=m[id];
tr[rt1].sum2+=v[id];
if(l==r) return;
int mid=l+r>>1;
if(pos<=mid) ins(ls(rt1),ls(rt2),l,mid,pos,id);
else ins(rs(rt1),rs(rt2),mid+1,r,pos,id);
}
ll query1(int rt1,int rt2,int l,int r,int ql,int qr){
if(ql<=l && r<=qr) return tr[rt1].sum1-tr[rt2].sum1;
int mid=l+r>>1;ll res=0;
if(ql<=mid) res+=query1(ls(rt1),ls(rt2),l,mid,ql,qr);
if(qr>mid) res+=query1(rs(rt1),rs(rt2),mid+1,r,ql,qr);
return res;
}
ll query2(int rt1,int rt2,int l,int r,int ql,int qr){
if(ql<=l && r<=qr) return tr[rt1].sum2-tr[rt2].sum2;
int mid=l+r>>1;ll res=0;
if(ql<=mid) res+=query2(ls(rt1),ls(rt2),l,mid,ql,qr);
if(qr>mid) res+=query2(rs(rt1),rs(rt2),mid+1,r,ql,qr);
return res;
}
}
using namespace President_tree;
struct Q{
int l,r,pos;ll tim;
friend inline bool operator < (Q a,Q b){return a.l<b.l;}
}a[N];
set<Q>S;
vector<Q>vec;
int tot;
int main(){
int n=read();
for(int i=1;i<=n;i++){
s[i]=read(),m[i]=read(),v[i]=read();
if(v[i]) t[i]=(m[i]-1)/v[i]+1;
else t[i]=1e10;
}
sort(t+1,t+n+1);
tot=unique(t+1,t+n+1)-t-1;
for(int i=1;i<=n;i++){
int pos;
if(v[i]) pos=lower_bound(t+1,t+tot+1,(m[i]-1)/v[i]+1)-t;
else pos=tot;
ins(rt[i],rt[i-1],1,tot,pos,i);
}
for(int i=1;i<=n;i++){
Q tmp;tmp.l=tmp.r=i;tmp.pos=s[i];tmp.tim=0;
S.insert(tmp);
}
int q=read();
while(q--){
int Time=read(),l=read(),r=read();
Q tmp;tmp.pos=0;tmp.l=l;tmp.r=r;tmp.tim=Time;
set<Q>::iterator it=S.upper_bound(tmp);--it;
int cur=0;
while(1){
if((*it).l>r || it==S.end()) break;
vec.pb((*it));
++cur;++it;
}
for(int i=0;i<cur;i++) S.erase(S.find(vec[i]));
if(vec[0].l<l){
Q tmp1;
tmp=vec[0];tmp1=tmp;tmp1.r=l-1;
S.insert(tmp1);vec[0].l=l;
}
if(vec[cur-1].r>r){
Q tmp1;
tmp=vec[cur-1];tmp1=tmp;tmp1.l=r+1;
S.insert(tmp1);vec[cur-1].r=r;
}
tmp.pos=0;tmp.l=l;tmp.r=r;tmp.tim=Time;
S.insert(tmp);
ll ans=0;
for(int i=0;i<cur;i++){
if(vec[i].tim){
int pos=upper_bound(t+1,t+tot+1,Time-vec[i].tim)-t-1;
if(pos) ans+=query1(rt[vec[i].r],rt[vec[i].l-1],1,tot,1,pos);
ans+=query2(rt[vec[i].r],rt[vec[i].l-1],1,tot,pos+1,tot)*(Time-vec[i].tim);
}
else ans+=min(m[vec[i].l],s[vec[i].l]+Time*(v[vec[i].l]));
}
vec.clear();
cout<<ans<<"\n";
}
return 0;
}