[NOIP2022] 比赛

给定长度为 \(n\) 的排列 \(a\)\(b\)。有 \(q\) 次询问,每次询问给定 \(l\)\(r\),求 \(\sum\limits_{l \leq p \leq q \leq r} (\max\limits_{i=p}^{q} a_i) \times (\max\limits_{i=p}^{q} b_i)\)\(2^{64}\) 取模后的结果。

\(1 \leq n,q \leq 2.5 \times 10^5\)

离线处理。考虑对 \(r\) 进行扫描线,记当前的 \(r\)\(r_0\)。我们需要对于每个 \(l\) 维护 \(x_l=\max\limits_{i=l}^{r_0} a_i\)\(y_l=\max\limits_{i=l}^{r_0} b_i\)。容易发现,在移动 \(r\) 时,我们需要对 \(x_l\)\(y_l\) 进行一些区间修改。考虑使用栈维护 \(x\)\(y\) 的值域连续段,这样就可以将区间修改变为 \(O(n)\) 次区间加了。

考虑我们需要维护 \(x\)\(y\) 的区间加,以及区间 \(x_i \times y_i\) 的历史和。考虑直接上矩阵维护。

我们对于线段树的每个区间维护矩阵 \(\begin{bmatrix}sum_i & xysum_i & xsum_i & ysum_i & len_i\end{bmatrix}\)。其中 \(sum_i\) 表示区间 \(i\) 的历史和,\(xysum_i\) 表示区间 \(i\)\(x \times y\) 之和,\(xsum_i\) 表示区间 \(i\)\(x\) 之和,\(ysum_i\) 表示区间 \(i\)\(y\) 之和,\(len_i\) 表示区间 \(i\) 的长度。则对于区间 \(i\) 的所有 \(x\) 值加 \(num\),不更新 \(sum_i\) 时,在矩阵中表示为下面的形式:

\[\begin{bmatrix} sum_i & xysum_i & xsum_i & ysum_i & len_i \end{bmatrix} \times \begin{bmatrix} 1 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & num & 0 & 1 & 0 \\ 0 & 0 & num & 0 & 1 \end{bmatrix} = \begin{bmatrix} sum'_i & xysum'_i & xsum'_i & ysum'_i & len'_i \end{bmatrix} \]

对于所有 \(y\) 值加 \(num\),表示为:

\[\begin{bmatrix} sum_i & xysum_i & xsum_i & ysum_i & len_i \end{bmatrix} \times \begin{bmatrix} 1 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 \\ 0 & num & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & num & 1 \end{bmatrix} = \begin{bmatrix} sum'_i & xysum'_i & xsum'_i & ysum'_i & len'_i \end{bmatrix} \]

接下来我们需要更新所有的 \(sum\),这表现为:

\[\begin{bmatrix} sum_i & xysum_i & xsum_i & ysum_i & len_i \end{bmatrix} \times \begin{bmatrix} 1 & 0 & 0 & 0 & 0 \\ 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} sum'_i & xysum'_i & xsum'_i & ysum'_i & len'_i \end{bmatrix} \]

初始时矩阵为 \(\begin{bmatrix} 0 & 0 & 0 & 0 & len_i \end{bmatrix}\),查询时我们只需要知道 \(sum_i\) 即可。根据实验,转移矩阵的乘积一定会形如下面的形式,其中红色字母代表当前位置的值需要动态维护,代码里面的数与其意义相同:

\[ \begin{bmatrix} 1 & 0 & 0 & 0 & 0 \\ \color{red}{x_1} & 1 & 0 & 0 & 0 \\ \color{red}{x_2} & \color{red}{x_3} & 1 & 0 & 0 \\ \color{red}{x_4} & \color{red}{x_5} & 0 & 1 & 0 \\ \color{red}{x_6} & \color{red}{x_7} & \color{red}{x_8} & \color{red}{x_9} & 1 \end{bmatrix} \]

我们维护这 \(9\) 个数即可。

总的时间复杂度为 \(O(n \log n)\),还需要带上矩阵乘法。

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
using namespace std;
struct Matrix{
	unsigned long long x1,x2,x3,x4,x5,x6,x7,x8,x9;
}I=(Matrix){0,0,0,0,0,0,0,0,0},U=(Matrix){1,0,0,0,0,0,0,0,0};
struct Matrix2{
	unsigned long long x1,x2,x3,x4,x5;
};
Matrix operator *(const Matrix &lhs,const Matrix &rhs){
	Matrix hs;
	hs.x1=lhs.x1+rhs.x1;
	hs.x2=lhs.x2+lhs.x3*rhs.x1+rhs.x2;
	hs.x3=lhs.x3+rhs.x3;
	hs.x4=lhs.x4+lhs.x5*rhs.x1+rhs.x4;
	hs.x5=lhs.x5+rhs.x5;
	hs.x6=lhs.x6+lhs.x7*rhs.x1+lhs.x8*rhs.x2+lhs.x9*rhs.x4+rhs.x6;
	hs.x7=lhs.x7+lhs.x8*rhs.x3+lhs.x9*rhs.x5+rhs.x7;
	hs.x8=lhs.x8+rhs.x8;
	hs.x9=lhs.x9+rhs.x9;
	return hs;
}
Matrix2 operator *(const Matrix2 &lhs,const Matrix &rhs){
	Matrix2 hs;
	hs.x1=lhs.x1+lhs.x2*rhs.x1+lhs.x3*rhs.x2+lhs.x4*rhs.x4+lhs.x5*rhs.x6;
	hs.x2=lhs.x2+lhs.x3*rhs.x3+lhs.x4*rhs.x5+lhs.x5*rhs.x7;
	hs.x3=lhs.x3+lhs.x5*rhs.x8;
	hs.x4=lhs.x4+lhs.x5*rhs.x9;
	hs.x5=lhs.x5;
	return hs;
}
Matrix2 operator +(const Matrix2 &lhs,const Matrix2 &rhs){
	Matrix2 hs;
	hs.x1=lhs.x1+rhs.x1;
	hs.x2=lhs.x2+rhs.x2;
	hs.x3=lhs.x3+rhs.x3;
	hs.x4=lhs.x4+rhs.x4;
	hs.x5=lhs.x5+rhs.x5;
	return hs;
}
unsigned long long a[250010],b[250010];
struct Segment{
	int l,r;
	Matrix tag;
	Matrix2 mat;
}seg[1000010];
void pushdown(int id){
	seg[id*2].mat=seg[id*2].mat*seg[id].tag;
	seg[id*2].tag=seg[id*2].tag*seg[id].tag;
	seg[id*2+1].mat=seg[id*2+1].mat*seg[id].tag;
	seg[id*2+1].tag=seg[id*2+1].tag*seg[id].tag;
	seg[id].tag=I;
}
void pushup(int id){
	seg[id].mat=seg[id*2].mat+seg[id*2+1].mat;
}
void build(int id,int l,int r){
	seg[id].l=l;
	seg[id].r=r;
    seg[id].tag=I;
	if(l==r){
		seg[id].mat=(Matrix2){0,0,0,0,1};
		seg[id].tag=I;
	}
	else{
		int mid=(l+r)>>1;
		build(id*2,l,mid);
		build(id*2+1,mid+1,r);
		pushup(id);
	}
}
void modify(int id,int l,int r,Matrix dif){
	if(l<=seg[id].l  &&  seg[id].r<=r){
		seg[id].mat=seg[id].mat*dif;
		seg[id].tag=seg[id].tag*dif;
		return ;
	}
	pushdown(id);
	if(l<=seg[id*2].r){
		modify(id*2,l,r,dif);
	}
	if(seg[id*2+1].l<=r){
		modify(id*2+1,l,r,dif);
	}
	pushup(id);
}
unsigned long long query(int id,int l,int r){
	if(l<=seg[id].l  &&  seg[id].r<=r){
		return seg[id].mat.x1;
	}
	pushdown(id);
	unsigned long long sum=0;
	if(l<=seg[id*2].r){
		sum+=query(id*2,l,r);
	}
	if(seg[id*2+1].l<=r){
		sum+=query(id*2+1,l,r);
	}
	return sum;
}
struct Node{
	int l,r;
	unsigned long long val;
};
struct Query{
	int l,id;
};
unsigned long long ans[250010];
vector<Query> offline[250010];
int main(){
	int test_id,n;
	scanf("%d %d",&test_id,&n);
	for(int i=1;i<=n;i++){
		scanf("%llu",&a[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%llu",&b[i]);
	}
	int q;
	scanf("%d",&q);
	for(int i=1;i<=q;i++){
		int l,r;
		scanf("%d %d",&l,&r);
		offline[r].push_back((Query){l,i});
	}
	build(1,1,n);
	stack<Node> st_a,st_b;
	for(int i=1;i<=n;i++){
		int l_a=i;
		modify(1,i,i,(Matrix){0,0,0,0,a[i],0,0,a[i],0});
		while(!st_a.empty()  &&  st_a.top().val<a[i]){
			int l=st_a.top().l,r=st_a.top().r;
			unsigned long long val=st_a.top().val;
			st_a.pop();
			modify(1,l,r,(Matrix){0,0,0,0,a[i]-val,0,0,a[i]-val,0});
			l_a=l;
		}
		st_a.push((Node){l_a,i,a[i]});
		int l_b=i;
		modify(1,i,i,(Matrix){0,0,b[i],0,0,0,0,0,b[i]});
		while(!st_b.empty()  &&  st_b.top().val<b[i]){
			int l=st_b.top().l,r=st_b.top().r;
			unsigned long long val=st_b.top().val;
			st_b.pop();
			modify(1,l,r,(Matrix){0,0,b[i]-val,0,0,0,0,0,b[i]-val});
			l_b=l;
		}
		st_b.push((Node){l_b,i,b[i]});
		modify(1,1,n,U);
		for(int j=0;j<offline[i].size();j++){
			int l=offline[i][j].l,id=offline[i][j].id;
			ans[id]=query(1,l,i);
		}
	}
	for(int i=1;i<=q;i++){
		printf("%llu\n",ans[i]);
	}
	return 0;
}
posted @ 2025-11-24 22:27  Oken喵~  阅读(15)  评论(1)    收藏  举报