[Ynoi2019] Happy Sugar Life 做题记录

省流:二维数点+分块
这里直接看的别人的题解,思路是来自于这篇题解

这里给他进行一些补充:单块内只有\(O(B^2)\)个询问,但是处理答案的时候要离线求,不然空间复杂度是\(O(n\sqrt n)\)无法接受。对于二维前缀和的具体形式,我们设我们分块的是\(x\)轴,那么考虑\(y\)轴的变化,记录我们要求的\(y\)轴为\(l,r\),我们需要实现的是对于一个二位数点\([l,r-1],[r,n]\)增加,查询直接查询\(l,r\),注意此处要离散化,不然空间复杂度就会成为\(O(n^2)\),然后\(2,3\)块的处理相当于互换一下\(x,y\)轴,其余的应该比较好理解了,具体可以参考代码(个人认为可读性还是比较强的,有几个变量名有点抽象,但是根据我的写法也应该能猜出来对应的哪一个部分。)
代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+10,B=500;
struct edge{
	int x;
	int y;
	int xx;
	int yy;
	int gg;
	int ll1;
	int ll2;
	long long ans;
}wen[maxn];
int n,m,p[maxn],val[maxn],C[maxn],mu,pre[maxn],zhui[B+10][B+10],lin[maxn];
int lst[maxn],nxt[maxn],cnt,li[maxn],last,tp;
vector<int>cao[maxn];
inline int lowbit(int q){
	return q&(-q);
}
inline void add(int q,int w){
	for(int i=q;i<=n;i+=lowbit(i)){
		C[i]+=w;
	}
	return;
}
inline int query(int q){
	int he=0;
	for(int i=q;i;i-=lowbit(i)){
		he+=C[i];
	}
	return he;
}
inline void solve(){
	for(int i=1;i<=m;i++){
		wen[i].gg=0;
	}
	for(int l=1,r;l<=n;l=r+1){
		r=min(l+B-1,n);
		for(int i=1;i<=n;i++){
			pre[i]=0;
		}
		for(int i=l;i<=r;i++){
			pre[p[i]]++;
		}
		for(int i=1;i<=n;i++){
			pre[i]+=pre[i-1];
		}
		cnt=0;
		for(int i=l;i<=r;i++){
			li[++cnt]=p[i];
		}
		sort(li+1,li+1+cnt);
		cnt=unique(li+1,li+1+cnt)-li-1;
		tp=0;
		last=0;
		for(int i=1;i<=n;i++){
			while(tp<cnt&&li[tp+1]<=i){
				tp++;
				last=tp;
			}
			lst[i]=last;
		}
		tp=cnt+1;
		last=tp;
		for(int i=n;i>=1;i--){
			while(tp>0&&li[tp-1]==i){
				tp--;
				last=tp;
			}
			nxt[i]=last;
		}
		for(int i=1;i<=cnt;i++){
			for(int j=1;j<=cnt;j++){
				zhui[i][j]=0;
			}
		}
		for(int i=l;i<=r;i++){
			for(int j=i+1;j<=r;j++){
				if(p[i]<p[j]){
					zhui[nxt[p[i]]][nxt[p[j]]]++;
					zhui[nxt[p[j]]][nxt[p[j]]]--;
				}
			}
		}
		for(int i=1;i<=cnt;i++){
			for(int j=1;j<=cnt;j++){
				zhui[i][j]+=zhui[i][j-1];
			}
		}
		for(int i=1;i<=cnt;i++){
			for(int j=1;j<=cnt;j++){
				zhui[i][j]+=zhui[i-1][j];
			}
		}
		for(int i=1;i<=m;i++){
			if(wen[i].x<=l&&r<=wen[i].y){
				wen[i].ans-=wen[i].gg*(pre[wen[i].yy]-pre[wen[i].xx-1]);
				wen[i].ans-=zhui[lst[wen[i].xx-1]][lst[wen[i].yy]];
				wen[i].gg+=pre[wen[i].xx-1];
			}
			else if(r>=wen[i].x&&l<=wen[i].y){
				for(int j=max(l,wen[i].x);j<=min(r,wen[i].y);j++){
					if(p[j]<wen[i].xx){
						wen[i].gg++;
					}
					else if(p[j]<=wen[i].yy){
						wen[i].ans-=wen[i].gg;
					}
				}
			}
		}
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>p[i];
	}
	for(int i=1;i<=m;i++){
		cin>>wen[i].x>>wen[i].y>>wen[i].xx>>wen[i].yy;
		cao[wen[i].x-1].push_back(i);
		cao[wen[i].y].push_back(i);
	}
	for(int i=1;i<=n;i++){
		val[i]=query(p[i]);
		add(p[i],1);
		for(int j=0;j<cao[i].size();j++){
			mu=cao[i][j];
			if(wen[mu].x-1==i){
				wen[mu].ll1=query(wen[mu].xx-1);
				wen[mu].ll2-=query(wen[mu].yy)-query(wen[mu].xx-1);
			}
			else{
				wen[mu].ll2+=query(wen[mu].yy)-query(wen[mu].xx-1);
				wen[mu].ans-=wen[mu].ll1*wen[mu].ll2;
			}
		}
	}
	for(int i=1;i<=n;i++){
		C[i]=0;
	}
	for(int i=1;i<=n;i++){
		add(p[i],val[i]);
		for(int j=0;j<cao[i].size();j++){
			mu=cao[i][j];
			if(wen[mu].x-1==i){
				wen[mu].ans-=query(wen[mu].yy)-query(wen[mu].xx-1);
			}
			else{
				wen[mu].ans+=query(wen[mu].yy)-query(wen[mu].xx-1);
			}
		}
	}
	solve();
	for(int i=1;i<=n;i++){
		lin[p[i]]=i;
	}
	for(int i=1;i<=n;i++){
		p[i]=lin[i];
	}
	for(int i=1;i<=m;i++){
		swap(wen[i].x,wen[i].xx);
		swap(wen[i].y,wen[i].yy);
	}
	solve();
	for(int i=1;i<=m;i++){
		cout<<wen[i].ans<<'\n';
	}
	return 0;
}
posted @ 2025-07-17 10:59  特别之处  阅读(21)  评论(0)    收藏  举报