Loading

【题解】[JOI 2021 Final] ダンジョン 3

贪心神题。

手算一下不难得到 \(\mathcal{O}(N^2)\) 的贪心。

我们从 \(S\) 点出发,每次选择与当前点距离 \(\le U\)\(B\) 最小的点,如果这个点的 \(B\) 比当前点小,则将能量填充至恰好到达该点,否则就将燃料填满。

直接二分可以做到 \(\mathcal{O}(N^2)\) ,离线一下可以 \(\mathcal{O}(N^2)\)

接下来是最关键的模型转换,我们将这个过程转化为线段覆盖的模型。

对于每一层,我们看成数轴上的一个点,相邻两点的距离就是 \(A\) 。我们将第 \(i\) 个点的位置记作 \(S_i\)

对于在第 \(i\) 层恢复 \(j\) 的能量,相当于以 \(B_i\) 的单位代价覆盖线段 \([S_i,S_i+j]\)

\(U_i\) 的限制条件,相当于以 \(B_i\) 的单位代价,只能选择覆盖线段 \([S_i,S_i+U_i]\)

注意上面的覆盖不一定从 \(S_i\) 开始,因为开始一段可以被前面的点覆盖。

那么如果 \(U\) 是定值,我们只用开一个栈维护覆盖每个区间的最小的代价。时间复杂度 \(\mathcal{O}(N\log N)\)

接着考虑子任务 \(3\)\(T_{i}=N+1\),非常明显地提示了考虑对询问按 \(S\) 从大到小排序的离线。

\(U\) 会变化,考虑观察一下当 \(S,T\) 固定事,随着 \(U\) 的变化答案会怎么变。

随着 \(U\) 的增大,答案越来越小,对于每一层,都是先慢慢覆盖后面的一段,然后停滞不前,接着被前面更优的层覆盖(如果存在更优的),最后被完全覆盖。

这四部分都是关于 \(U\) 的一次函数。

第一部分是形如 \(y=kx(k>0)\) 的函数,对应的区间是从 \(0\) 开始一直到,第 \(i\) 层在碰到后面第一个 \(B_j<B_i\)\(j\) 层之后停止。

第二部分是形如 \(y=a\) 的函数,\(a\) 是常数,对应的区间是停止向后扩展,但还没有被前面更优的区间覆盖。

第三部分是形如 \(y=kx+b(k<0)\) ,的函数,对应的区间是当前层正在被前面第一个 \(\le B_i\) 的区间覆盖。

被完全覆盖后的贡献为 \(0\) ,这一部分可以省略。

这样我们运用子任务 \(2\) 的单调栈找出每一层前面和后面的更优区间。然后倒叙枚举当前区间,用树状数组维护这若干个分段函数的和。

具体操作是用两个树状数组维护每一个位置此时的斜率和截距,\(U\) 的范围很大,需要离散化。

对于 \(T_i\) 任意的情况,考虑转化为子任务 \(3\)

我们发现在 \([S_i,T_i]\) 中与 \(T_i\) 的距离 \(\le U_i\)\(B\) 最小的位置 \(x\) ,覆盖 \([x,N+1]\) 时在 \(T_i\) 后面的覆盖方案与 \([S_i,N+1]\) 相同,在\(T_i\) 前面时是连续的一段,前者是子任务 \(3\) ,后者可以 \(\mathcal{O(1)}\) 求得。所以我们只用先二分出对应区间,然后用 ST表 找出位置 \(x\)

时间复杂度 \(\mathcal{O}(N\log N)\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 200005
#define int long long
using namespace std;
int n,m,a[N],b[N],t,lg[N],c[2][N],o[N],u[N],T,s[N],sta[N],top,pr[N],nx[N],ans[N];
struct node{int s,t,u;}q[N];
namespace st1{
	int f[N][20];
	inline int ck(int x,int y){if(b[x]<b[y])return x;return y;}
	int ask(int l,int r){int cur=lg[r-l+1];return ck(f[l][cur],f[r-(1<<cur)+1][cur]);}
	void init(){
		rep(i,1,n+1)f[i][0]=i;
		rep(j,1,t)rep(i,1,n-(1<<j)+2)f[i][j]=ck(f[i][j-1],f[i+(1<<(j-1))][j-1]);
	}
}
namespace st2{
	int f[N][20];
	inline int ck(int x,int y){if(a[x]>a[y])return x;return y;}
	int ask(int l,int r){int cur=lg[r-l+1];return ck(f[l][cur],f[r-(1<<cur)+1][cur]);}
	void init(){
		rep(i,1,n+1)f[i][0]=i;
		rep(j,1,t)rep(i,1,n-(1<<j)+2)f[i][j]=ck(f[i][j-1],f[i+(1<<(j-1))][j-1]);
	}
}
inline void add(int op,int x,int val){for(;x<=T;x+=x&-x)c[op][x]+=val;}
inline int ask(int op,int x){int sum=0;for(;x;x-=x&-x)sum+=c[op][x];return sum;}
inline void change(int op,int l,int r,int k){
	if(l>r)return;
	l=lower_bound(u+1,u+T+1,l)-u;
	r=upper_bound(u+1,u+T+1,r)-u-1;
	add(op,l,k);add(op,r+1,-k);
}
vector<node>w[N];vector<int>dl[N];
signed main(){
	scanf("%lld%lld",&n,&m);t=log2(n+1);
	lg[0]=-1;rep(i,1,n)lg[i]=lg[i>>1]+1;
	rep(i,1,n)scanf("%lld",&a[i]),s[i+1]=s[i]+a[i];
	rep(i,1,n)scanf("%lld",&b[i]);
	st1::init();st2::init();
	rep(i,1,m)scanf("%lld%lld%lld",&q[i].s,&q[i].t,&q[i].u),o[i]=q[i].u;
	sort(o+1,o+m+1);rep(i,1,m)if(o[i]!=o[i-1])u[++T]=o[i];
	//printf("aa ");rep(i,1,n+1)printf("%lld ",s[i]);putchar('\n');
	//printf("bb ");rep(i,1,T)printf("%lld ",u[i]);putchar('\n');
	rep(i,1,m){
		int l=q[i].s,r=q[i].t-1,ed=q[i].t-1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(s[q[i].t]-s[mid]<=q[i].u)ed=mid,r=mid-1;
			else l=mid+1;
		}
		int cur=st1::ask(ed,q[i].t-1);
		//printf("ss %lld %lld %lld\n",i,ed,cur);
		node now;now.u=q[i].u,now.s=i,now.t=1;
		w[q[i].s].push_back(now);
		now.s=i,now.t=-1;w[cur].push_back(now);
		ans[i]+=(s[q[i].t]-s[cur])*b[cur];
	}
	pre(i,n,1){
		while(top&&b[sta[top]]>=b[i]){
			pr[sta[top]]=i;top--;
		}
		if(top)nx[i]=sta[top];
		sta[++top]=i;
	}
	rep(i,1,n)if(!nx[i])nx[i]=n+1;
	//rep(i,1,n)printf("%lld ",pr[i]);putchar('\n');
	//rep(i,1,n)printf("%lld ",nx[i]);putchar('\n');
	pre(i,n,1){
		change(0,0,s[nx[i]]-s[i],b[i]);
		change(1,s[nx[i]]-s[i]+1,0x7fffffff,b[i]*(s[nx[i]]-s[i]));
		dl[pr[i]].push_back(i);
		for(int j=0;j<(int)dl[i].size();j++){
			int x=dl[i][j];
			change(0,s[x]-s[i],s[nx[x]]-s[i],-b[x]);
			change(1,s[x]-s[i],s[nx[x]]-s[i],b[x]*(s[x]-s[i]));
			change(1,s[nx[x]]-s[i]+1,0x7fffffff,-b[x]*(s[nx[x]]-s[x]));
		}
		for(int j=0;j<(int)w[i].size();j++){
			int cur=lower_bound(u+1,u+T+1,w[i][j].u)-u;
			//cout<<"uu "<<i<<" "<<w[i][j].s<<" "<<w[i][j].t<<" "<<(w[i][j].u*ask(0,cur)+ask(1,cur))<<endl;
			ans[w[i][j].s]+=w[i][j].t*(w[i][j].u*ask(0,cur)+ask(1,cur));
		}
	}
	rep(i,1,m){
		if(q[i].u<a[st2::ask(q[i].s,q[i].t-1)])puts("-1");
		else printf("%lld\n",ans[i]);
	}
	return 0;
} 
/*
5 1
2 0 1 1 1 
4 3 5 7 4 
4 5 6
*/
posted @ 2021-06-06 17:59  7KByte  阅读(107)  评论(0编辑  收藏  举报