【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;
}
posted @ 2022-11-15 08:15  ez_lcw  阅读(60)  评论(0编辑  收藏  举报