[NOIP2022] 比赛
[NOIP2022] 比赛
很明显要离线,枚举右端点
对于\([L,R]\)中取子区间的最大值求和不是很好维护
定义\(f_l\)为当前左端点为\(l\),\(\sum\limits_{r=l}^RAns(l,r)\)
\(Query(l,r)\)就是\(\sum\limits_{i=l}^rf_i\),我们可以用线段树维护
定义\(ma_l\)为当前\(R\),\(A\)中\((l,R)\)的最大值,\(mb_l\)同理
考虑我们加入一个\(R\)对\(f,ma,mb\)的影响
很明显,\(ma,mb\)就是与\(A_R,B_R\)取\(max\),又因为\(ma,mb\)单增为了方便我们找到第一个\(R\)大于的用区间覆盖维护
对于\(f\),其实就相当于对于\([1,R]\)所有的\(f_l+=(ma_l\times mb_l)\)
令\(ma_l=x,mb_l=y\)
如果我们把线段树节点上的\(f\)拆分为\(c_{xy}\sum xy+c_x\sum x+c_y\sum y+c\sum1\),则上面的操作到线段树上就是\(c_{xy}+=1\)
而如果是区间覆盖实际上是可以做这样的拆分的:
\[Case1:A,B都没被覆盖
\\
没影响
\\
Case2:A覆盖,B没
\\
则xy,x要变,其中的c_{xy}\sum{xy}=c_{xy}x'\sum y,相当于这一项的系数到y上
\\
c_x到常数项
\\
Case3:B覆盖,A没
\\
同理
\\
Case4:A,B都被覆盖
\\
都到常数项
\]
由此,覆盖操作经拆分依旧可以互相转化
最后就是打标记的问题了,因为上面的我们要系数的增量,如果当前儿子有覆盖标记的话,下传的增量标记是要转化的
这里我们规定先传增量再传覆盖,这样保证所有增量在覆盖前面,维护的\(\sum xy\)对应的增量也是未覆盖的
#include<bits/stdc++.h>
#define int unsigned long long
#define ls 2*p
#define rs 2*p+1
using namespace std;
int T,n;
const int MAXN=2.5e5+5;
int a[MAXN];
int b[MAXN];
int q;
unsigned long long Ans[MAXN];
vector<pair<int,int> >query[MAXN];
int l,r;
struct Tag{
unsigned long long addx,addy,addxy,addc;
int clox,cloy;
};
struct Seg{
unsigned long long datex,datey,datexy,date;
int l,r;
Tag lazy;
}Tree[MAXN*4];
void Build(int p,int l,int r)
{
Tree[p].l=l;
Tree[p].r=r;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
}
void Put(Seg &u,int Len,Tag t)
{
if(u.lazy.clox&&u.lazy.cloy)
{
u.lazy.addc+=t.addxy*u.lazy.clox*u.lazy.cloy+t.addx*u.lazy.clox+t.addy*u.lazy.cloy+t.addc;
}
else if(u.lazy.clox)
{
u.lazy.addy+=t.addxy*u.lazy.clox+t.addy;
u.lazy.addc+=t.addx*u.lazy.clox+t.addc;
}
else if(u.lazy.cloy)
{
u.lazy.addx+=t.addxy*u.lazy.cloy+t.addx;
u.lazy.addc+=t.addy*u.lazy.cloy+t.addc;
}
else
{
u.lazy.addxy+=t.addxy;
u.lazy.addx+=t.addx;
u.lazy.addy+=t.addy;
u.lazy.addc+=t.addc;
}
if(t.clox)
{
u.lazy.clox=t.clox;
}
if(t.cloy)
{
u.lazy.cloy=t.cloy;
}
u.date+=u.datex*t.addx+u.datey*t.addy+u.datexy*t.addxy+Len*t.addc;
if(t.clox&&t.cloy)
{
u.datex=t.clox*Len;
u.datey=t.cloy*Len;
u.datexy=t.clox*t.cloy*Len;
}
else if(t.clox)
{
u.datex=t.clox*Len;
u.datexy=u.datey*t.clox;
}
else if(t.cloy)
{
u.datey=t.cloy*Len;
u.datexy=u.datex*t.cloy;
}
}
void push_up(int p)
{
Tree[p].date=Tree[ls].date+Tree[rs].date;
Tree[p].datex=Tree[ls].datex+Tree[rs].datex;
Tree[p].datey=Tree[ls].datey+Tree[rs].datey;
Tree[p].datexy=Tree[ls].datexy+Tree[rs].datexy;
}
void Clear(Tag &x)
{
x.addc=0;
x.addx=0;
x.addy=0;
x.addxy=0;
x.clox=0;
x.cloy=0;
return;
}
Tag Make(int clox,int cloy,unsigned long long addx,unsigned long long addy,unsigned long long addc,unsigned long long addxy)
{
Tag nyh520;
nyh520.clox=clox;
nyh520.cloy=cloy;
nyh520.addx=addx;
nyh520.addy=addy;
nyh520.addc=addc;
nyh520.addxy=addxy;
return nyh520;
}
void push_down(int p)
{
Put(Tree[ls],Tree[ls].r-Tree[ls].l+1,Tree[p].lazy);
Put(Tree[rs],Tree[rs].r-Tree[rs].l+1,Tree[p].lazy);
Clear(Tree[p].lazy);
// if((Tree[p].lazy.clox||Tree[p].lazy.cloy))
// {
// printf("why\n");
// }
}
void Update(int p,int l,int r,Tag x)
{
if(Tree[p].l>=l&&Tree[p].r<=r)
{
Put(Tree[p],Tree[p].r-Tree[p].l+1,x);
return;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid)
{
Update(ls,l,r,x);
}
if(r>mid)
{
Update(rs,l,r,x);
}
push_up(p);
}
int twice;
unsigned long long Query(int p,int l,int r)
{
if(Tree[p].l>=l&&Tree[p].r<=r)
{
return Tree[p].date;
}
// if(twice&&(Tree[p].lazy.clox||Tree[p].lazy.cloy))
// {
// printf("wdg\n");
// }
push_down(p);
// if((Tree[p].lazy.clox||Tree[p].lazy.cloy))
// {
// printf("why\n");
// }
int mid=(Tree[p].l+Tree[p].r)>>1;
unsigned long long Res=0;
if(l<=mid)
{
Res+=Query(ls,l,r);
}
if(r>mid)
{
Res+=Query(rs,l,r);
}
push_up(p);
return Res;
}
int dp1[MAXN][25];
int dp2[MAXN][25];
int Query1(int x,int y)
{
int k=log2(y-x+1);
return max(dp1[x][k],dp1[y-(1<<k)+1][k]);
}
int Query2(int x,int y)
{
int k=log2(y-x+1);
return max(dp2[x][k],dp2[y-(1<<k)+1][k]);
}
signed main()
{
scanf("%llu %llu",&T,&n);
for(int i=1;i<=n;i++)
{
scanf("%llu",&a[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%llu",&b[i]);
}
for(int i=1;i<=n;i++)
{
dp1[i][0]=a[i];
}
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
dp1[i][j]=max(dp1[i][j-1],dp1[i+(1<<j-1)][j-1]);
}
}
for(int i=1;i<=n;i++)
{
dp2[i][0]=b[i];
}
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
dp2[i][j]=max(dp2[i][j-1],dp2[i+(1<<j-1)][j-1]);
}
}
scanf("%llu",&q);
for(int i=1;i<=q;i++)
{
scanf("%llu %llu",&l,&r);
query[r].push_back(make_pair(l,i));
}
Build(1,1,n);
for(int i=1;i<=n;i++)
{
l=1;
r=i;
int key=i;
while(l<=r)
{
int mid=(l+r)>>1;
if(Query1(mid,i)==a[i])
{
key=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
Update(1,key,i,Make(a[i],0,0,0,0,0));
// printf("%d ",key);
l=1;
r=i;
key=i;
while(l<=r)
{
int mid=(l+r)>>1;
if(Query2(mid,i)==b[i])
{
key=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
Update(1,key,i,Make(0,b[i],0,0,0,0));
Update(1,1,i,Make(0,0,0,0,0,1));
//printf("%d\n",key);
for(int j=0;j<query[i].size();j++)
{
pair<int,int>efc=query[i][j];
Ans[efc.second]=Query(1,efc.first,i);
twice=1;
if(Query(1,efc.first,i)!=Query(1,efc.first,i))
{
printf(">fgg\n");
}
twice=0;
}
}
for(int i=1;i<=q;i++)
{
printf("%llu\n",Ans[i]);
}
}