Yet Another Range Query Problem 题解

我们考虑这个东西并不好维护,我们可以离线下来差分求解答案,我们又发现这个\(\min*\max\)难以维护,那么我们开一个\(5\times5\)的矩阵,像这样定义:\([\sum \min,\sum \max, \sum{\min \times \max} , history~sum,size]\),我们发现我们把一个区间统一赋值成一个\(\min\)或者\(\max\)可以给他乘上一个矩阵,以\(\min\)举例,假设我们要更改为\(x\)

\[\begin{bmatrix} 0& 0 & 0 & 0 &0 \\ 0& 1 & x & 0 &0 \\ 0& 0 & 0 & 0 &0 \\ 0& 0 & 0 & 1 &0 \\ x& 0 & 0 & 0 &1 \end{bmatrix} \]

统计历史和也显然可以使用矩阵进行维护。

鉴于卡常后可读性为0,挂上一版卡常前的代码供参考。

代码:

#include <bits/stdc++.h>
#define int long long
#define lid (id<<1)
#define rid (id<<1|1)
#define mid ((l+r)>>1)
using namespace std;
const int modd=1e9+7;
const int maxn=2e5+10;
struct node{
	int a[5][5];
	void init(){
		for(int i=0;i<5;i++){
			for(int j=0;j<5;j++){
				a[i][j]=0;
			}
		}
		return;
	}
	const node operator *(const node &q)const{
		node qw;
		qw.init();
		for(int i=0;i<5;i++){
			for(int j=0;j<5;j++){
				for(int k=0;k<5;k++){
					qw.a[i][j]=(qw.a[i][j]+a[i][k]*q.a[k][j])%modd;
				}
			}
		}
		return qw;
	}
	const node operator +(const node &q)const{
		node qw;
		qw.init();
		for(int i=0;i<5;i++){
			for(int j=0;j<5;j++){
				qw.a[i][j]=a[i][j]+q.a[i][j];
				qw.a[i][j]=qw.a[i][j]>=modd?qw.a[i][j]-modd:qw.a[i][j];
			}
		}
		return qw;
	}
}chu,minn,maxx;
struct edge{
	node lazy;
	node val;
	bool tag;
}tree[maxn<<2];
int n,m,ans[maxn],a[maxn],x,y,xx,yy,tp1,st1[maxn],tp2,st2[maxn];
vector<pair<int,pair<int,int> > >Q[maxn];
inline void push_tag(int id,node q){
	if(tree[id].tag){
		tree[id].lazy=tree[id].lazy*q;
	}
	else{
		tree[id].lazy=q;
		tree[id].tag=1;
	}
	tree[id].val=tree[id].val*q;
	return;
}
inline void push_down(int id){
	if(tree[id].tag){
		push_tag(lid,tree[id].lazy);
		push_tag(rid,tree[id].lazy);
		tree[id].tag=0;
		return;
	}
}
inline void push_up(int id){
	tree[id].val=tree[lid].val+tree[rid].val;
	return;
}
inline void news(int id,int l,int r,int q){
	if(l==r){
		tree[id].val.a[0][4]=1;
		return;
	}
	if(q<=mid){
		news(lid,l,mid,q);
	}
	else{
		news(rid,mid+1,r,q);
	}
	push_up(id);
	return;
}
inline void add(int id,int l,int r,int q,int w,node qw){
	if(q<=l&&r<=w){
		push_tag(id,qw);
		return;
	}
	push_down(id);
	if(q<=mid){
		add(lid,l,mid,q,w,qw);
	}
	if(w>mid){
		add(rid,mid+1,r,q,w,qw);
	}
	push_up(id);
	return;
}
inline int query(int id,int l,int r,int q,int w){
	if(q<=l&&r<=w){
		return tree[id].val.a[0][3];
	}
	push_down(id);
	if(w<=mid){
		return query(lid,l,mid,q,w);
	}
	else if(q>mid){
		return query(rid,mid+1,r,q,w);
	}
	else{
		return (query(lid,l,mid,q,w)+query(rid,mid+1,r,q,w))%modd;
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	chu.a[0][0]=1;
	chu.a[1][1]=1;
	chu.a[2][2]=1;
	chu.a[2][3]=1;
	chu.a[3][3]=1;
	chu.a[4][4]=1;
	minn.a[1][1]=1;
	minn.a[3][3]=1;
	minn.a[4][4]=1;
	maxx.a[0][0]=1;
	maxx.a[3][3]=1;
	maxx.a[4][4]=1;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=m;i++){
		cin>>x>>y>>xx>>yy;
		Q[yy].push_back({i,{x,y}});
		Q[xx-1].push_back({-i,{x,y}});
	}
	for(int i=1;i<=n;i++){
		while(tp1&&a[i]<a[st1[tp1]]){
			tp1--;
		}
		news(1,1,n,i);
		minn.a[1][2]=a[i];
		minn.a[4][0]=a[i];
		add(1,1,n,st1[tp1]+1,i,minn);
		st1[++tp1]=i;
		while(tp2&&a[i]>a[st2[tp2]]){
			tp2--;
		}
		maxx.a[0][2]=a[i];
		maxx.a[4][1]=a[i];
		add(1,1,n,st2[tp2]+1,i,maxx);
		st2[++tp2]=i;
		add(1,1,n,1,i,chu);
		for(int j=0;j<Q[i].size();j++){
			if(Q[i][j].first<0){
				ans[-Q[i][j].first]-=query(1,1,n,Q[i][j].second.first,Q[i][j].second.second);
			}
			else{
				ans[Q[i][j].first]+=query(1,1,n,Q[i][j].second.first,Q[i][j].second.second);
			}
		}
	}
	for(int i=1;i<=m;i++){
		cout<<(ans[i]%modd+modd)%modd<<'\n';
	}
	return 0;
}
posted @ 2025-05-06 17:02  特别之处  阅读(22)  评论(0)    收藏  举报