EZ_XHX
2023-04-16 15:28:23
我们要实现标记与标记,信息与信息,标记与信息的合并。
标记与标记:原来的懒标记与新的懒标记之间的合并。push_down
标记的信息:原来的信息与新的懒标记之间的合并。push_down
信息与信息:主要涉及push_up的操作。
简单来说,就是有幺元与运算满足结合律的群。线段树的标记与信息都是幺半群。
为什么在线段树上要满足结合律,因为你标记统计起来再下放要与一个一个下放一样的。
线段树标记与信息的合并可以用矩阵的思路比如区间加乘求和:
思考:区间加区间乘区间历史和?
题意:给定两个排列
我们就可以预处理
然后我们查询按右端点排序之后就转化为了区间覆盖--区间历史和问题。
就是
我们设计信息
那么我们对于每一次
我们每次就要查询区间
我们对于后面的要快速求出
#include<bits/stdc++.h>
#define mid (l+r)/2
#define lc x<<1
#define rc x<<1|1
#define int unsigned long long
using namespace std;
const int maxn=25e4+5;
int T,n,a[maxn],b[maxn],ans[maxn];
struct query{int l,r;}q[maxn];
bool cmp(query a,query b){return a.r<b.r;}
struct Que{int ll,id;};
vector<Que> Qu[maxn];
struct Tag{
int a,b,lh,ah,bh,ch;
void apply(const Tag &r){
*this={
r.a?:a,//如果说标记后加入,那么它在后面进行覆盖
r.b?:b,
lh+r.lh+a*r.ah+b*r.bh+a*b*r.ch,
ah+(a?0:r.ah+b*r.ch),
bh+(b?0:r.bh+a*r.ch),
ch+((a||b)?0:r.ch)
};
}
};
struct Info{
int suma,sumb,sumc,hsum;
void apply(const Tag &r,int len){
hsum+=len*r.lh+suma*r.ah+sumb*r.bh+sumc*r.ch;
suma=(r.a?len*r.a:suma);sumb=(r.b?len*r.b:sumb);
sumc=len*r.a*r.b+(r.a?0:r.b*suma)+(r.b?0:r.a*sumb)+(r.b||r.a ?0:sumc);
}
Info operator +(const Info &r) const{
return {suma+r.suma,sumb+r.sumb,sumc+r.sumc,hsum+r.hsum};
}
};
stack<int> sta,stb;
Info Tr[maxn<<2];
Tag tag[maxn<<2];
int Q;
void update(int x,int l,int r,const Tag &xx){
Tr[x].apply(xx,r-l+1);
tag[x].apply(xx);//表示对于两个进行操作
}
void push_down(int x,int l,int r){
update(lc,l,mid,tag[x]),update(rc,mid+1,r,tag[x]);
tag[x]=(Tag){0,0,0,0,0,0};//表示形成幺元
}
void push_up(int x){Tr[x]=Tr[lc]+Tr[rc];}
void build(int x,int l,int r){
if(l==r) return;
build(lc,l,mid),build(rc,mid+1,r);//表示这里
}
void cover(int x,int l,int r,int ql,int qr,const Tag &xx){
if(l>qr||r<ql) return;
if(l>=ql&&r<=qr){
update(x,l,r,xx);
return;
}
push_down(x,l,r);
cover(lc,l,mid,ql,qr,xx);
cover(rc,mid+1,r,ql,qr,xx);
push_up(x);
}
int query(int x,int l,int r,int ql,int qr){
if(l>qr||r<ql) return 0;
if(l>=ql&&r<=qr) return Tr[x].hsum;
push_down(x,l,r);
return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>T>>n;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i) cin>>b[i];
cin>>Q;
for(int i=1;i<=Q;++i){
cin>>q[i].l>>q[i].r;
Qu[q[i].r].push_back((Que){q[i].l,i});//表示这里的
}
sort(q+1,q+Q+1,cmp);
build(1,1,n);
for(int r=1;r<=n;++r){//一个一个进行操作
while((!sta.empty())&&a[sta.top()]<=a[r]) sta.pop();
while((!stb.empty())&&b[stb.top()]<=b[r]) stb.pop();
int ua=sta.empty()?1:sta.top()+1;
int ub=stb.empty()?1:stb.top()+1;
sta.push(r);stb.push(r);
cover(1,1,n,ua,r,(Tag){a[r],0,0,0,0,0}),cover(1,1,n,ub,r,(Tag){0,b[r],0,0,0,0});
cover(1,1,n,1,r,(Tag){0,0,0,0,0,1});//表示Ch给hsum的贡献为1
for(auto [l,id]:Qu[r]) ans[id]=query(1,1,n,l,r);
}
for(int i=1;i<=Q;++i) cout<<ans[i]<<endl;
return 0;
}