G - Add and Multiply Queries
2个单点,一个询问,感觉询问只能O(n)做
但是发现查询答案保证在1e18以下 2^60
也就是说b[i]>1最多60个
也就是说需要判断的地方最多60个,其他地方可以用区间和优化
用set or vector 记录b[i]>1的位置,二分找到就可以做区间和了
就写完了
// Problem: [ABC368G] Add and Multiply Queries
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/AT_abc368_g
// Memory Limit: 1 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<set>
using namespace std;
typedef long long ll;
const int N=1e5+9;
int a[N],b[N];
int n;
struct BIT{
ll val;
}t[N];
ll lowbit(int x){return x&(-x);}
void update(int x,ll k){
for(int i=x;i<=n;i+=lowbit(i)){
t[i].val+=k;
}
}
ll getsum(ll x){
ll res=0;
for(int i=x;i>0;i-=lowbit(i)){
res+=t[i].val;
}
return res;
}
ll query(int l,int r){
if(l>r){
return 0;
}else{
return getsum(r)-getsum(l-1);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
update(i,a[i]);
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
set<int> st;
st.insert(0);
st.insert(n+1);//边界
for(int i=1;i<=n;i++){
if(b[i]>1){
st.insert(i);
}
}
int q;
cin>>q;
for(int i=1;i<=q;i++){
int op,l,r;
cin>>op>>l>>r;
if(op==1){
update(l,r-query(l,l));
}else if(op==2){
if(b[l]==1 && r!=1){
st.insert(l);
}
if(b[l]!=1 && r==1){
st.erase(l);
}
b[l]=r;
}else{
ll ans=query(l,l);
l++;
auto it=st.lower_bound(l);
while(l<=r){
if(b[l]!=1){//最多60次
ans=max(ans+query(l,l),ans*b[l]);
it++,l++;
}else{
ans+=query(l,min(*it-1,r));
l=*it;
}
}
cout<<ans<<'\n';
}
}
return 0;
}