题意
给定两个长度为 \(n\) 的非负整数序列 \(A,B\),并定义数列 \(C\),\(C_i = \max\limits_{j=1}^{i}{A_i}\)。
有 \(q\) 次操作,每次对 \(A\) 和 \(B\) 的某个位置进行修改,然后询问 \(\prod \limits_{i=1}^{n} \min\{B_i,C_i\} \bmod 10^9+7\)。保证修改之后不小于原数。
\(1 \leq n ,q \leq 10^5\),任意时刻 \(0 \leq A_i,B_i \leq 10^9\)
题解
考虑一个修改的影响。\(B\) 的影响是单点的,但修改 \(A_i\) 的影响是一段以 \(i\) 开始的区间。
注意到这个区间修改比较阴间,因为维护的信息非常怪,不太能我不会线段树维护。考虑分块,维护块内的答案。对于修改 \(B_i\) 直接暴力重构块就行了。接下来重点讨论怎么维护修改了 \(A_i\) 之后的 \(C\)。
我们发现 \(A_i\) 被修改了之后会产生一个 \([i,n]\) 的 \(C\) 序列区间取 \(\max\) 操作。套路,散块暴力重构,整块直接打标记。考虑 \(\operatorname{tag}=k\) 的时候的答案。
分类讨论。
-
\(B_j \leq C_j\)
此时 \(j\) 的贡献一定是 \(B_i\)。
-
\(C_j \leq \operatorname{tag} \leq B_j\)
此时贡献是 \(\operatorname{tag}\)。
-
\(C_j \leq B_j \leq \operatorname{tag}\)
此时贡献是 \(B_j\)。
-
\(\operatorname{tag} \leq C_j \leq \operatorname{B_j}\)
贡献是 \(C_j\)。
考虑把贡献不为 \(\operatorname{tag}\) 的部分记下来,记作 \(mul\)。贡献为 \(\operatorname{tag}\) 的部分直接记录指数 \(c\)。显然第一种情况的 \(B_j\) 要乘到 \(mul\) 里面。然后维护后面三种情况。注意到 \(\operatorname{tag}\) 单调不减,于是一个 \(j\) 的贡献一定是先在第四种情况,然后第二种,最后第三种。
把所有 \(B_j \geq C_j\) 的 \(C_j\) 和 \(B_j\) 放一起排序,\(\operatorname{tag}\) 从前往后扫所有比它小的数,扫到一个 \(C_j\) 就说明是第二种情况,\(mul\) 除掉 \(C_j\),然后贡献多了一个 \(\operatorname{tag}\)。扫到一个 \(B_j\) 说明是第三种情况了,贡献少一个 \(\operatorname{tag}\),\(mul\) 乘上 \(B_j\)。
块内答案就是 \(mul \times \operatorname{tag}^{c}\),于是查询是根号的。
复杂度还有个快速幂的 \(\log\) 和排序的 \(\operatorname{log}\),于是是 \(O(n \sqrt n \log \max W)\),其中 \(W\) 是值域,默认 \(n,q\) 同阶。
另外可能会乘 \(0\) 和除 \(0\),需要精细实现一下。具体见代码。
# include <bits/stdc++.h>
const int N=100010,INF=0x3f3f3f3f,BLEN=410,MOD=1e9+7;
typedef long long ll;
int bsiz,blo[N];
int n,m;
int tc[N],tb[N],ta[N];
inline int qpow(ll d,ll p){
ll ans=1;
while(p){
if(p&1) ans=ans*d%MOD;
p>>=1,d=d*d%MOD;
}
return ans;
}
struct Prod{ // 支持乘 0 和除 0
int z,cur; // z 是现在乘了的 0 的个数, cur 是除了 0 以外部分的乘积
inline void setv(int x){
z=0,cur=x;
return;
}
inline void mul(int x){
x?(cur=1ll*cur*x%MOD):(++cur);
return;
}
inline void div(int x){
x?(cur=1ll*cur*qpow(x,MOD-2)%MOD):(--cur);
return;
}
inline int getv(void){
return (!z)*cur;
}
};
struct Block{
int len,c[BLEN],b[BLEN],tag,pos,lbc,L,R;
Prod ans;
std::vector <std::pair <int,int> > S;
inline void init(int cl,int cr){ // 初始化
len=cr-cl+1,L=cl,R=cr;
for(int i=0;i<len;++i) c[i+1]=tc[cl+i],b[i+1]=tb[cl+i];
return;
}
inline void remake(void){ // 暴力重构
for(int i=1;i<=len;++i) c[i]=std::max(c[i],tag); // 下放标记
ans.setv(1);
for(int i=1;i<=len;++i) ans.mul(std::min(c[i],b[i]));
S.clear();
for(int i=1;i<=len;++i) if(b[i]>c[i]) S.push_back(std::make_pair(b[i],1)),S.push_back(std::make_pair(c[i],0));
std::sort(S.begin(),S.end()),pos=lbc=0; // 归零 c 和 pos, 重新排序
}
inline void modifytag(int x){
if(x<=tag) return;
tag=x;
while(pos<(int)S.size()&&S[pos].first<=tag){
if(S[pos].second) --lbc,ans.mul(S[pos].first);
else ++lbc,ans.div(S[pos].first);
++pos;
}
return;
}
inline int query(void){
return 1ll*ans.getv()*qpow(tag,lbc)%MOD;
}
}B[BLEN];
inline int read(void){
int res,f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-')f=-1;
res=c-48;
while((c=getchar())>='0'&&c<='9')
res=res*10+c-48;
return res*f;
}
void print(int x){
if(x>9) print(x/10);
putchar(x%10+'0');
return;
}
signed main(void){
n=read(),m=read(),bsiz=floor(sqrt(n)+0.5);
for(int i=1;i<=n;++i) ta[i]=read(),blo[i]=(i-1)/bsiz+1;
for(int i=1;i<=n;++i) tb[i]=read(),tc[i]=std::max(tc[i-1],ta[i]);
for(int i=1;i<=blo[n];++i){
B[i].init((i-1)*bsiz+1,std::min(i*bsiz,n)),B[i].remake();
}
while(m--){
int opt=read(),pos=read(),v=read();
if(opt){
int idx=blo[pos];
B[idx].b[pos-B[idx].L+1]=v;
B[idx].remake(); // 重构块
}else{
int idx=blo[pos];
for(int i=pos;i<=B[idx].R;++i) B[idx].c[i-B[idx].L+1]=std::max(B[idx].c[i-B[idx].L+1],v); // 散块暴力修改
B[idx].remake(); // 重构
for(int i=idx+1;i<=blo[n];++i) B[i].modifytag(v);
}
int ans=1;
for(int i=1;i<=blo[n];++i) ans=1ll*ans*B[i].query()%MOD;
print(ans),puts("");
}
return 0;
}