[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\) 时,在矩阵中表示为下面的形式:
对于所有 \(y\) 值加 \(num\),表示为:
接下来我们需要更新所有的 \(sum\),这表现为:
初始时矩阵为 \(\begin{bmatrix} 0 & 0 & 0 & 0 & len_i \end{bmatrix}\),查询时我们只需要知道 \(sum_i\) 即可。根据实验,转移矩阵的乘积一定会形如下面的形式,其中红色字母代表当前位置的值需要动态维护,代码里面的数与其意义相同:
我们维护这 \(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;
}

浙公网安备 33010602011771号