1. 人品rmq
首先因为我们先修改再查询,这个问题实际上是二维的。
那么不妨考虑将整个平面直角坐标系的横轴看时间轴,纵轴看成序列,那么相当于有
先考虑一个暴力的想法,我们能否维护所有时刻的序列呢?
先分析修改,我们考虑扫描线掉。将修改
然后再考虑修改,用类似的思路,假设初始的序列是
这是一个看起来可以优化的暴力的思路。不妨考虑一个弱化的问题,询问都跨过同一个时间点。将询问拆成两部分,放在时间点
我们考虑一些分治方法来解决这个问题。只需要不重不漏地找到分割点且可以优秀地回答上面的问题就好了。于是考虑猫树分治。
树上的每一个结点存下子树内都会执行的操作,以及当前结点需要做的操作。询问则挂在第一个中点在询问间的结点。剩下的就是直接做了。
注意到这样的话每个位置的操作和查询只会执行
有一些小细节,比如修改应该先减再加(不然历史最大值会出错),以及每次线段树的复原(每个结点的历史最大值及其标记变为当前的值及标记,注意到 push_down 要主动下放直到孙子结点,即两层下放),可以参考代码实现。
void insmodify(LL l,LL r,LL now,LL x,LL y,LL id)
{
if(x<=l && r<=y) return trm[now].push_back(id);
tre[now].push_back(id);
Mm;
if(x<=mid) insmodify(l,mid,lc(now),x,y,id);
if(mid<y) insmodify(mid+1,r,rc(now),x,y,id);
}
void insquery(LL l,LL r,LL now,LL x,LL y,LL id)
{
Mm;
if(l==r || (x<=mid && mid<y)) return req[now].push_back(id);
if(x<=mid) insquery(l,mid,lc(now),x,y,id);
else insquery(mid+1,r,rc(now),x,y,id);
}
struct segTree{
struct node{
LL l,r;
LL maxn;
LL bmax;
LL ta,tb;
}tr[2000005];
bool tag[2000005];
inline void push_up(LL now){tr[now].bmax=max(tr[lc(now)].bmax,tr[rc(now)].bmax),tr[now].maxn=max(tr[lc(now)].maxn,tr[rc(now)].maxn);}
inline void reset(LL u){tr[u].bmax=tr[u].maxn,tr[u].tb=tr[u].ta,tag[u]=true;}
void push_tag(LL now,LL ta,LL tb,bool flag=false)
{
if(!flag && tr[now].l!=tr[now].r && tag[now]) push_down(now,true);
tr[now].bmax=max(tr[now].bmax,tr[now].maxn+tb),tr[now].tb=max(tr[now].tb,tr[now].ta+tb),tr[now].maxn+=ta,tr[now].ta+=ta;
}
void push_down(LL now,bool flag=false)
{
if(tr[now].ta || tr[now].tb) push_tag(lc(now),tr[now].ta,tr[now].tb,flag),push_tag(rc(now),tr[now].ta,tr[now].tb,flag),tr[now].ta=tr[now].tb=0;
if(tag[now]) reset(lc(now)),reset(rc(now)),tag[now]=false;
}
void build(LL l,LL r,LL now)
{
tr[now].l=l,tr[now].r=r;
tr[now].ta=tr[now].tb=0;
if(l==r)
{
tr[now].maxn=tr[now].bmax=0;
return ;
}
Mm;
build(l,mid,lc(now)),build(mid+1,r,rc(now));
push_up(now);
}
void modify(LL now,LL x,LL y,LL k)
{
LL l=tr[now].l,r=tr[now].r;
if(x<=l && r<=y) return push_tag(now,k,k);
push_down(now);
Mm;
if(x<=mid) modify(lc(now),x,y,k);
if(mid<y) modify(rc(now),x,y,k);
push_up(now);
}
LL query(LL now,LL x,LL y)
{
LL l=tr[now].l,r=tr[now].r;
if(x<=l && r<=y) return tr[now].bmax;
push_down(now);
Mm;
LL ret=0;
if(x<=mid) ret=max(query(lc(now),x,y),ret);
if(mid<y) ret=max(query(rc(now),x,y),ret);
return ret;
}
}segt;
vector<LL> catQ[50005],add[50005],sub[50005];
void Solve(LL now,LL l,LL r)
{
Mm;
for(auto id:trm[now]) segt.modify(1,mdf[id].rp,mdf[id].rq,mdf[id].v);
if(l^r) Solve(lc(now),l,mid),Solve(rc(now),mid+1,r);
if(req[now].empty())
{
for(auto id:trm[now]) segt.modify(1,mdf[id].rp,mdf[id].rq,-mdf[id].v);
return ;
}
for(auto id:req[now]) catQ[qry[id].lp].push_back(id),catQ[qry[id].lq].push_back(id);
for(auto id:tre[now])
{
LL L=mdf[id].lp,R=mdf[id].lq;
if(R<=mid)
{
add[R].push_back(id);
sub[max(L-1,l-1)].push_back(id);
}
else if(L>mid)
{
add[L].push_back(id);
sub[min(R+1,r+1)].push_back(id);
}
else
{
add[mid].push_back(id);
add[mid+1].push_back(id);
sub[max(L-1,l-1)].push_back(id);
sub[min(R+1,r+1)].push_back(id);
}
}
segt.reset(1);
for(LL i=mid;i>=l-1;--i)
{
for(auto id:sub[i]) segt.modify(1,mdf[id].rp,mdf[id].rq,-mdf[id].v);
for(auto id:add[i]) segt.modify(1,mdf[id].rp,mdf[id].rq,mdf[id].v);
if(i!=l-1) for(auto id:catQ[i]) ans[id]=max(ans[id],segt.query(1,qry[id].rp,qry[id].rq));
}
segt.reset(1);
for(LL i=mid+1;i<=r+1;++i)
{
for(auto id:sub[i]) segt.modify(1,mdf[id].rp,mdf[id].rq,-mdf[id].v);
for(auto id:add[i]) segt.modify(1,mdf[id].rp,mdf[id].rq,mdf[id].v);
if(i!=r+1) for(auto id:catQ[i]) ans[id]=max(ans[id],segt.query(1,qry[id].rp,qry[id].rq));
}
for(LL i=l;i<=r;++i) catQ[i].clear();
for(LL i=l-1;i<=r+1;++i) sub[i].clear(),add[i].clear();
for(auto id:trm[now]) segt.modify(1,mdf[id].rp,mdf[id].rq,-mdf[id].v);
}