【五一省选集训day4】Mansion

【五一省选集训day4】Mansion

注意,本题要求输出最大值,不要把最大值看成编号……srds 好像只有我看错了。

这个东西一看就很能用莫队做。

用莫队按 \(l\) 分块,再按 \(r\) 排序。维护一棵线段树,每次移动对线段树进行单点修改和区间求 \(\max\),一共 \(n\sqrt{n}\) 次移动,总时间复杂度是 \(O(n\sqrt{n}\log n)\) 的。可以获得 \(80pts\)

感觉根号是不好消的,但是这个 \(\log\) 就看起来很能优化。

因为是求 \(\max\) 我们考虑回滚莫队来避免减法。回滚莫队也是 \(O(n\sqrt{n})\) 的。注意到我们每次移动都要修改,修改 \(O(n\sqrt{n})\) 次,而查询最大值只有 \(O(n)\) 次。这个 \(\sqrt{n}\) 的差距让我们想到用分块来代替线段树做。线段树两种操作都是 \(\log\) 的,但分块是修改 \(O(1)\),查询 \(O(\sqrt{n})\) 的!改成分块,总时间复杂度 \(O\sqrt{n}\)

注意回滚莫队第一块除以 \(T\)\(0\),而为空的 \(que_0\) 除以 \(T\) 也是 \(0\),记得初始化 \(\frac{que_0}{T}=-1\),否则 \(0\) 会成为第一块开头,而不是 \(1\)害我调了一下午

code

#include<bits/stdc++.h>
//#define LOCAL
#define int ll
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
#define isdigit(x) ((x>='0')&&(x<='9'))
#define ls u<<1
#define rs u<<1|1
using namespace std;
typedef long long ll;
const int N=150500,T=395;
template <typename T>
inline void read(T &x){
	x=0;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}
template <typename T>
inline void write(T x){
	static int st[20];
	int cnt=0;
	do{
		st[cnt++]=x%10;
		x/=10;
	}while(x);
	while(cnt) putchar(st[--cnt]+'0');
}
template <typename T>
inline void write (T x,char ch){
	write(x);
	putchar(ch);
}
int n,m,q,t;
struct node{
	int a,b;
}h[N];
struct que{
	int t,id,l,r,vl,vr;
}qu[N];
int l,r,vl,vr;
bool cmp(que a,que b){
	return a.t!=b.t?a.t<b.t:a.r<b.r;
}
ll s[N],mx[N/T+10],mxt[N/T+10];
ll anss[N];
void add(int k){
	int a=h[k].a,b=h[k].b;
	s[a]+=b;
	int ta=a/T;
	mx[ta]=max(mx[ta],s[a]);
}
void add2(int k){
	int a=h[k].a,b=h[k].b;
	s[a]+=b;
	int ta=a/T;
	mxt[ta]=max(mxt[ta],s[a]);
}
void del2(int k){
	int a=h[k].a,b=h[k].b;
	s[a]-=b;
}
ll s2[N];
int L,R;
ll solve(ll l,ll r){
	ll ans=0;
	if(l/T==r/T){
		rep(i,l,r) ans=max(ans,s[i]);
	}else{
		rep(i,l,l/T*T+T-1) ans=max(ans,s[i]);
		rep(i,l/T+1,r/T-1) ans=max(ans,mxt[i]);
		rep(i,r/T*T,r) ans=max(ans,s[i]);
	}
	return ans;
}
signed main(){
	#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("my2.out","w",stdout);
	#endif
	read(n),read(m),read(q);
	rep(i,1,n){
		read(h[i].a);
	}
	rep(i,1,n) {
		read(h[i].b);
	}
	rep(i,1,q){
		read(l),read(r),read(vl),read(vr);
		qu[i]={l/T,i,l,r,vl,vr};
	}
	sort(qu+1,qu+q+1,cmp);
	qu[0].t=-1;
	rep(i,1,q){
		t=qu[i].t,l=qu[i].l,r=qu[i].r,vl=qu[i].vl,vr=qu[i].vr;
		ll ans=0;
		if(l/T==r/T){
			qu[i].t=qu[i-1].t;
			rep(j,l,r){
				int a=h[j].a,b=h[j].b;
				if(a<vl||a>vr) continue;
				s2[a]+=b;
				ans=max(ans,s2[a]);
			}
			rep(j,l,r){
				int a=h[j].a;
				s2[a]=0;
			}
		}else{
			L=t*T+T;
			if(t!=qu[i-1].t){
				memset(s,0,sizeof(s));
				memset(mx,0,sizeof(mx));
				R=L-1;
			}
			while(R<r) {
				R++;
				add(R);
			}
			memcpy(mxt,mx,sizeof(mx));
			while(L>l){
				L--;
				add2(L);
			}
			ans=solve(vl,vr);
			L=t*T+T;
			while(L>l){
				L--;
				del2(L);
			}
		}
		anss[qu[i].id]=ans;
	}
	rep(i,1,q) write(anss[i],'\n');
}
posted @ 2024-09-10 18:54  liyixin  阅读(5)  评论(0编辑  收藏  举报