【XSY4829】鸽子的彩灯(线段树)
大强说很套路,所以记一下。
首先当前的电流就是剩下还未经过的点亮的灯的 \(c_i\) 之和。
考虑一个暴力的做法:初始将所有询问的流量设为 \(0\),从后往前扫过每一个彩灯 \(i\),并把 \(p_i\in [l_j,r_j]\) 的询问 \(j\) 的流量都加上 \(c_i\),若某个询问的流量大于 \(s_i\),那么就把该询问的答案设为 \(i\) 并把该询问扔掉。
考虑证明两个区间有包含关系时,答案出现顺序也有对应的关系:发现对于相互包含的区间,大的区间肯定会比小的区间答案靠后。
那么假设当前所有未扔掉的区间中,有一个区间它被另一个区间包含,我们就先不考虑该区间。这样需要考虑的区间都是互不包含的,于是每次要修改流量的询问是排序后的一段区间的询问,那么就能用数据结构维护了。
每次在数据结构上找到流量最大的询问,如果其流量大于 \(s_i\) 就把它扔掉,此时会加入一些更小的被它包含的区间。用数据结构维护每个 \(R\) 对应的还未被考虑过的 \(L\) 最小的区间,然后每次找 \(R\) 在一段合法范围内的 \(L\) 最小的那个区间即可。
找到一个区间并准备将它设为考虑时,由于以前的 \(c_i\) 的贡献我们是没有给它考虑的,所以我们又需要一个数据结构来直接查询以前的 \(c_i\) 的贡献。
总时间复杂度 \(O(n\log n)\)。
#include<bits/stdc++.h>
#define N 500010
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
int qL[N],qR[N];
int n,m,s[N],c[N],p[N];
int idx,id[N],rk[N];
int ans[N];
vector<pair<int,int>> q[N];
namespace Seg1
{
pair<int,int> minl[N<<2];
pair<int,int> operator + (pair<int,int> a,pair<int,int> b)
{
if(a.first==b.first) return a.second>b.second?a:b;
return a.first<b.first?a:b;
}
void up(int k){minl[k]=minl[k<<1]+minl[k<<1|1];}
void build(int k,int l,int r)
{
if(l==r)
{
minl[k]=make_pair(q[l].empty()?INT_MAX:q[l].back().first,r);
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
up(k);
}
pair<int,int> query(int k,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return minl[k];
int mid=(l+r)>>1;
if(qr<=mid) return query(k<<1,l,mid,ql,qr);
if(ql>mid) return query(k<<1|1,mid+1,r,ql,qr);
return query(k<<1,l,mid,ql,qr)+query(k<<1|1,mid+1,r,ql,qr);
}
void update(int k,int l,int r,int x)
{
if(l==r)
{
assert(!q[l].empty());
q[l].pop_back();
minl[k]=make_pair(q[l].empty()?INT_MAX:q[l].back().first,r);
return;
}
int mid=(l+r)>>1;
if(x<=mid) update(k<<1,l,mid,x);
else update(k<<1|1,mid+1,r,x);
up(k);
}
}
set<pair<int,int>> sl,sr;
namespace Seg2
{
int lazy[N<<2];
pair<int,int> maxn[N<<2];
void up(int k){maxn[k]=max(maxn[k<<1],maxn[k<<1|1]);}
void downn(int k,int v){maxn[k].first+=v,lazy[k]+=v;}
void down(int k)
{
if(lazy[k])
{
downn(k<<1,lazy[k]);
downn(k<<1|1,lazy[k]);
lazy[k]=0;
}
}
void build(int k,int l,int r)
{
if(l==r)
{
maxn[k]=make_pair(-INT_MAX,l);
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
up(k);
}
void update(int k,int l,int r,int ql,int qr,int v)
{
if(ql<=l&&r<=qr){downn(k,v);return;}
down(k);
int mid=(l+r)>>1;
if(ql<=mid) update(k<<1,l,mid,ql,qr,v);
if(qr>mid) update(k<<1|1,mid+1,r,ql,qr,v);
up(k);
}
void update(int k,int l,int r,int x,int y)
{
if(l==r)
{
maxn[k]=make_pair(y,l);
return;
}
down(k);
int mid=(l+r)>>1;
if(x<=mid) update(k<<1,l,mid,x,y);
else update(k<<1|1,mid+1,r,x,y);
up(k);
}
}
namespace Seg3
{
#define lowbit(x) (x&-x)
int c[N];
inline void add(int x,int y){for(;x<=n;x+=lowbit(x))c[x]+=y;}
inline int query(int x){int ans=0;for(;x;x-=lowbit(x))ans+=c[x];return ans;}
inline int query(int l,int r){return query(r)-query(l-1);}
#undef lowbit
}
void rebuild(int nowl,int nowr,int nxtl,int lstr)
{
while(lstr<nowr)
{
auto seg=Seg1::query(1,1,n,lstr+1,nowr);
assert(seg.first>=nowl);
if(seg.first>=nxtl) return;
int l=seg.first,r=seg.second,qid=q[r].back().second;
Seg1::update(1,1,n,r);
Seg2::update(1,1,m,rk[qid],Seg3::query(l,r));
sl.insert(make_pair(l,rk[qid]));
sr.insert(make_pair(r,rk[qid]));
nowl=l,lstr=r;
}
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++) s[i]=read();
for(int i=1;i<=n;i++) c[i]=read();
for(int i=1;i<=n;i++) p[read()]=i;
for(int i=1;i<=m;i++)
{
int l=qL[i]=read(),r=qR[i]=read();
q[r].emplace_back(l,i);
}
for(int r=1;r<=n;r++)
{
for(auto pr:q[r]) id[rk[pr.second]=++idx]=pr.second;
sort(q[r].begin(),q[r].end());
reverse(q[r].begin(),q[r].end());
}
Seg1::build(1,1,n);
Seg2::build(1,1,m);
rebuild(1,n,n+1,0);
for(int i=n;i>=1;i--)
{
auto ql=sr.lower_bound(make_pair(p[i],0));
auto qr=sl.lower_bound(make_pair(p[i]+1,0));
if(ql!=sr.end()&&qr!=sl.begin())
{
qr--;
if((*ql).second<=(*qr).second)
Seg2::update(1,1,m,(*ql).second,(*qr).second,c[i]);
}
Seg3::add(p[i],c[i]);
while(1)
{
if(Seg2::maxn[1].first<=s[i]) break;
int rid=Seg2::maxn[1].second,qid=id[rid];
ans[qid]=i;
Seg2::update(1,1,m,rid,-INT_MAX);
sl.erase(make_pair(qL[qid],rid));
sr.erase(make_pair(qR[qid],rid));
auto nxt=sl.lower_bound(make_pair(qL[qid],0));
auto lst=sr.lower_bound(make_pair(qR[qid],0));
rebuild(qL[qid],qR[qid],nxt!=sl.end()?(*nxt).first:n+1,lst!=sr.begin()?(*(--lst)).first:0);
}
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}