有一堆区间加操作,还有一堆询问,每个询问可以从 [ s , t ] [s,t] [s,t]中选择一个非空子区间,执行序号在这个区间内的区间加操作,然后问 a k a_k ak的最大值。
首先可以先去掉一些条件,如果就是给一堆区间加操作,然后问选择一个子数组中的所有操作执行, a k a_k ak的最大值?。那显然我们应该只考虑覆盖 k k k这个位置的所有区间加操作,然后再这些操作里,他们都能对 k k k有效果,可以视为对 a k a_k ak的单点加,然后我们要选一个区间的操作,让区间元素和最大。这实际上就是一个最大子段和,可以dp。
然后如果我们加上操作序号必须在 [ s , t ] [s,t] [s,t]内这个条件,就相当于对一个区间的元素求最大子段和,这个东西可以线段数维护,和维护区间最长全0子串类似,也是维护三个 t a g tag tag:全局最大,前缀最大,后缀最大。具体来说,我们就是开一个线段树,存所有操作,如果第 i i i个操作可以区间加 x x x的话,则 t [ i ] = x t[i]=x t[i]=x,然后我们查序号在 [ s , t ] [s,t] [s,t]的所有操作的最大子段和,就是一个区间查 [ s , t ] [s,t] [s,t]
如果再加上 k k k每次询问都不同的话,那就还需要离线询问,确保每次查询 k k k的答案时,线段树中只含可以覆盖 k k k的所有区间。这可以用一个扫描线实现,每个操作都有个覆盖范围 [ l , r ] [l,r] [l,r],那我们可以从小到大遍历所有位置 i i i,在 l l l时加入这个操作,在 r r r时删除这个操作
struct Tree{
#define ls u<<1
#define rs u<<1|1
struct Node{
int l,r,mx,lmx,rmx,sum;
Node operator+(const Node &o){
Node res;
res.mx=max({mx,o.mx,rmx+o.lmx,o.lmx,rmx});
res.l=l;
res.r=o.r;
res.sum=sum+o.sum;
res.lmx=max(lmx,sum+o.lmx);
res.rmx=max(o.rmx,rmx+o.sum);
return res;
}
}tr[N<<2];
void pushup(int u){
tr[u]=tr[ls]+tr[rs];
}
void build(int u,int l,int r){
tr[u]={l,r,0,0,0,0};
if(l==r) return;
int mid=(l+r)>>1;
build(ls,l,mid); build(rs,mid+1,r);
pushup(u);
}
void modify(int u,int idx,int val){
if(tr[u].l==tr[u].r){
tr[u].sum=val;
tr[u].lmx=tr[u].rmx=tr[u].mx=val;
return;
}
else{
int mid=(tr[u].l+tr[u].r)>>1;
if(mid>=idx) modify(ls,idx,val);
else modify(rs,idx,val);
pushup(u);
}
}
Node query(int u,int l,int r){
if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
int mid=(tr[u].l+tr[u].r)>>1;
if(r<=mid)return query(ls,l,r);
if(l>mid)return query(rs,l,r);
return query(ls,l,r)+query(rs,l, r);
}
}t;
void solve(){
cin>>n>>m;
t.build(1,1,m);
vvi add[n+1],del[n+1];
rep(i,1,m){
int l,r,x;
cin>>l>>r>>x;
add[l].push_back({x,i});
del[r].push_back({x,i});
}
int qu;
cin>>qu;
vvi q[n+1];
vi ans(qu+1);
rep(i,1,qu){
int s,t,k;
cin>>k>>s>>t;
q[k].push_back({s,t,i});
}
rep(i,1,n){
for(auto &v:add[i]){
int id=v[1],val=v[0];
t.modify(1,id,val);
}
for(auto &v:q[i]){
int l=v[0],r=v[1],id=v[2];
ans[id]=t.query(1,l,r).mx;
}
for(auto &v:del[i]){
int id=v[1],val=v[0];
t.modify(1,id,0);
}
}
rep(i,1,qu){
cout<<ans[i]<<'\n';
}
}