题目分析:
这个权值一看就可以使用线段树维护啊,因为很明显可以进行高效合并。
对于区间合并其实就只是需要判断一下两个区间中间如果是乘号,那么造成的贡献要变成区间两边乘起来的贡献,而不是区间两边加起来的贡献。
所以我们其实就是要维护这么几个信息:\(lmul,rmul\) 区间左边/右边极长的一段乘的结果,\(opt\) 区间最右边的符号是什么,\(res\) 这个区间的权值是多少,\(sz\) 代表这个区间的长度。
这样我们就顺利地完成了不带修改的问题,那么考虑带上修改怎么做呢。
如果是修改符号的话显然就可以直接修改这几个信息,只是需要多维护 \(sum\) 代表区间和,\(mul\) 代表区间乘,用来替换 \(res\),\(lx\) 代表区间最左边的数是多少,因为无论怎么修改 \(lmul\) 至少也要是 \(lx\)。
而如果是修改数值的话其实不是很容易,假设当前区间内,长度为 \(i\) 的连续乘的极长的段的数量为 \(cnt[i]\),那么意味着我们的权值会变成 \(\sum_{i=1} x^i cnt[i]\)。
如果我们直接对于 \(cnt\) 把数组开到 \(n\) 的话空间复杂度就是 \(O(n^2)\) 就很显然不可以。
这个时候就有一个想法就是分块,假设我们的区间长度为 \(len\),那么我们的 \(cnt\) 数组只开到 \(\sqrt{len}\),对于大于 \(\sqrt{len}\) 的部分,我们不以桶的形式存储而是直接以数值存到数组里,因为大于 \(\sqrt{len}\) 的部分的个数不会超过 \(\sqrt{len}\) 个,所以总的空间复杂度就是 \(O(n\sqrt{n})\)。处理了这个那么我们的修改数值就很简单了。
此时我们在区间合并的时候也要记得把 \(cnt\) 数组和记录的数组进行合并。
这样的话单次操作复杂度就是 \(O(\sqrt{n}) + O(\sqrt{\frac{n}{2}}) + \cdots = O(\sqrt{n})\)
这个题即卡时间又卡空间,所以需要实现的精细一点。
代码:
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100500;
const int MOD = 1e9+7;
long long a[N],b[N];
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int mod(int x){
if(x < 0) return (x % MOD + MOD) % MOD;
return x % MOD;
}
int power(int a,int b){
int res = 1;
while(b){
if(b & 1) res = mod(res * a);
a = mod(a * a);
b >>= 1;
}
return res;
}
struct SGT{
int sum,mul,lx,tagx,tago,mx,sz,llen,lmul,rlen,rmul,res;
bool opt;
int *cnt;
vector<int> v;
void init(int a,bool b){
res = lx = mul = sum = a;
lmul = a,llen = 1;opt = b;
if(b) rmul = a,rlen = 1;
else rmul = 1,rlen = 0;
cnt[0] = 0;cnt[1] = 1;
}
void init(int len){
mx = sqrt(len);sz = len;cnt = new int[mx+1];
for(int i=0; i<=mx; i++) cnt[i] = 0;
tagx = tago = -1;mul = 1;
}
void updatex(int x){
res = 0;sum = mod(x * sz);mul = power(x,sz);
lx = x,lmul = power(x,llen),rmul = power(x,rlen);
for(int i=1,tmp=x; i<=mx; i++,tmp=mod(tmp*x)) res = mod(res + cnt[i] * tmp);
//emmm 乘法忘取模问题严重
for(int i : v) res = mod(res + power(x,i));
tagx = x;
}
void updateo(bool o){
opt = tago = o;
for(int i=0; i<=mx; i++) cnt[i] = 0;
v.clear();
if(o == 1){
if(sz > mx) v.push_back(sz);
else ++cnt[sz];
res = mul;llen = rlen = sz;
lmul = rmul = mul;
}
else{
res = sum;cnt[1] = sz;
llen = 1,lmul = lx; //默认数和右边的运算符绑定
rlen = 0,rmul = 1;
}
}
void pushdown(SGT &l,SGT &r){ //草,忘记了这里要引用
if(tagx != -1) l.updatex(tagx),r.updatex(tagx),tagx = -1;
if(tago != -1) l.updateo(tago),r.updateo(tago),tago = -1;
}
void pushup(SGT &l,SGT &r,bool flag){
opt = r.opt;sum = mod(l.sum + r.sum);mul = mod(l.mul * r.mul);lx = l.lx;
if(l.llen == l.sz && l.opt == 1) llen = l.llen + r.llen,lmul = mod(l.lmul * r.lmul);
else llen = l.llen,lmul = l.lmul;
if(r.rlen == r.sz && l.opt == 1) rlen = l.rlen + r.rlen,rmul = mod(l.rmul * r.rmul);
else rlen = r.rlen,rmul = r.rmul;
if(l.opt == 1) res = mod(l.res + r.res - l.rmul - r.lmul + l.rmul * r.lmul);
else res = mod(l.res + r.res);
if(!flag) return;
for(int i=0; i<=mx; i++) cnt[i] = 0;
v.clear();
int tmp1 = 0,tmp2 = 0,h = 0;
if(l.opt == 1) tmp1 = l.rlen,tmp2 = r.llen,h = tmp1 + tmp2;
if(tmp1 && tmp1 <= mx) cnt[tmp1]--,tmp1 = 0;
if(tmp2 && tmp2 <= mx) cnt[tmp2]--,tmp2 = 0;
if(h && h <= mx) cnt[h]++;
else if(h) v.push_back(h);
for(int i=1; i<=l.mx; i++) cnt[i] += l.cnt[i]; //一定要注意不要在这里指针越界啊!!!
for(int i=1; i<=r.mx; i++) cnt[i] += r.cnt[i];
for(int i : l.v){
if(i == tmp1) tmp1 = 0;
else if(i == tmp2) tmp2 = 0;
else if(i <= mx) cnt[i]++;
else v.push_back(i);
}
for(int i : r.v){
if(i == tmp1) tmp1 = 0;
else if(i == tmp2) tmp2 = 0;
else if(i <= mx) cnt[i]++;
else v.push_back(i);
}
}
}t[4*N];
struct node{
int llen,lmul,rlen,rmul,res,opt,sz;
//opt 维护区间最右侧的那个符号
};
node merge(node a,node b){
node c;
c.sz = a.sz + b.sz;c.opt = b.opt;
if(a.llen == a.sz && a.opt == 1) c.llen = a.llen + b.llen,c.lmul = mod(a.lmul * b.lmul);
else c.llen = a.llen,c.lmul = a.lmul;
if(b.rlen == b.sz && a.opt == 1) c.rlen = a.rlen + b.rlen,c.rmul = mod(a.rmul * b.rmul);
else c.rlen = b.rlen,c.rmul = b.rmul;
if(a.opt == 1) c.res = mod(a.res + b.res - a.rmul - b.lmul + a.rmul * b.lmul);
else c.res = mod(a.res + b.res);
return c;
}
void build(int now,int now_l,int now_r){
t[now].init(now_r - now_l + 1);
if(now_l == now_r){
t[now].init(a[now_l],b[now_l]);
return;
}
int mid = (now_l + now_r)>>1;
build(now<<1,now_l,mid);build(now<<1|1,mid+1,now_r);
t[now].pushup(t[now<<1],t[now<<1|1],true);
}
void modifyx(int now,int now_l,int now_r,int l,int r,int x){
if(l <= now_l && r >= now_r){
t[now].updatex(x);
// printf("t[%lld]=%lld,%lld,%lld\n",now,t[now].opt,t[now].lx,t[now].res);
return;
}
t[now].pushdown(t[now<<1],t[now<<1|1]);
int mid = (now_l + now_r)>>1;
if(l <= mid) modifyx(now<<1,now_l,mid,l,r,x);
if(r > mid) modifyx(now<<1|1,mid+1,now_r,l,r,x);
t[now].pushup(t[now<<1],t[now<<1|1],false);
// printf("t[%lld]=%lld,%lld,%lld\n",now,t[now].opt,t[now].lx,t[now].res);
}
void modifyo(int now,int now_l,int now_r,int l,int r,bool x){
if(l <= now_l && r >= now_r){
t[now].updateo(x);
return;
}
t[now].pushdown(t[now<<1],t[now<<1|1]);
int mid = (now_l + now_r)>>1;
if(l <= mid) modifyo(now<<1,now_l,mid,l,r,x);
if(r > mid) modifyo(now<<1|1,mid+1,now_r,l,r,x);
t[now].pushup(t[now<<1],t[now<<1|1],true);
}
node query(int now,int now_l,int now_r,int l,int r){
// printf("t[%lld]=%lld,%lld,%lld\n",now,t[now].llen,t[now].rlen,t[now].res);
if(l <= now_l && r >= now_r) return {t[now].llen,t[now].lmul,t[now].rlen,t[now].rmul,t[now].res,t[now].opt,t[now].sz};
t[now].pushdown(t[now<<1],t[now<<1|1]);
int mid = (now_l + now_r)>>1;
if(r <= mid) return query(now<<1,now_l,mid,l,r);
if(l > mid) return query(now<<1|1,mid+1,now_r,l,r);
return merge(query(now<<1,now_l,mid,l,r),query(now<<1|1,mid+1,now_r,l,r));
}
signed main(){
// freopen("in.txt","r",stdin);
// freopen("ans.txt","w",stdout);
int n,m;n=read(),m=read();
for(int i=1; i<=n; i++) a[i] = read(),a[i] = mod(a[i]);
for(int i=1; i<=n-1; i++) b[i] = read();
build(1,1,n);
for(int i=1; i<=m; i++){
int opt,l,r,x;opt = read();l=read();r=read();
if(opt != 3) x=read();
if(opt == 1) modifyx(1,1,n,l,r,x%MOD);
else if(opt == 2) modifyo(1,1,n,l,r,x);
else if(opt == 3) printf("%lld\n",query(1,1,n,l,r).res);
}
return 0;
}