CF438D 题解
前言
这是一棵区间膜线段树,与花神游历各国 很像,都是维护区间最值来优化暴力。
做法
线段树维护区间膜很麻烦,因为膜(mod)运算对于一个数减小得很快,所以考虑暴力区间修改。
但是要优化,不然会T飞掉。
怎么优化?
我们发现,有 $ x mod p < p$ 这个性质,所以当$ x \leq p$时,膜操作是无意义的。
于是,我们在暴力修改时,可以维护一个区间最大值,如果最大值是小于等于取膜的数,就不用递归下去。
然后就做完了。
Code
#include<iostream> #include<cstdio> using namespace std; #define int long long inline int read(){ register int x=0,v=1,ch=getchar(); while(!isdigit(ch)){if(ch=='-')v=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();} return x*v; } const int MAX=100005; int n,m,a[MAX]; int op,x; struct Seg{ int sum,mx; }tree[MAX<<2]; inline int Max(int a,int b){ return a>b?a:b; } inline void pushup(int x){ tree[x]=(Seg){tree[x<<1].sum+tree[x<<1|1].sum,Max(tree[x<<1].mx,tree[x<<1|1].mx)}; } void build(int x,int l,int r){ if(l==r){ tree[x]=(Seg){a[l],a[l]}; return ; } register int mid=l+r>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); pushup(x); } void modify(int x,int l,int r,int s,int t,int v){ if(l==r){ tree[x]=(Seg){tree[x].sum%v,tree[x].mx%v}; return ; } register int mid=l+r>>1; if(s<=mid&&tree[x<<1].mx>=v)modify(x<<1,l,mid,s,t,v); if(mid<t&&tree[x<<1|1].mx>=v)modify(x<<1|1,mid+1,r,s,t,v); pushup(x); } void change(int x,int l,int r,int s,int v){ if(l==r){ tree[x]=(Seg){v,v}; return ; } register int mid=l+r>>1; if(s<=mid)change(x<<1,l,mid,s,v); else change(x<<1|1,mid+1,r,s,v); pushup(x); } int query(int x,int l,int r,int s,int t){ if(s<=l&&r<=t)return tree[x].sum; register int res=0,mid=l+r>>1; if(s<=mid)res+=query(x<<1,l,mid,s,t); if(mid<t)res+=query(x<<1|1,mid+1,r,s,t); return res; } int l,r; signed main(){ n=read(),m=read(); for(register int i=1;i<=n;++i)a[i]=read(); build(1,1,n); while(m--){ op=read(); l=read(),r=read(); if(op==1){ printf("%lld\n",query(1,1,n,l,r)); }else if(op==2){ x=read(); modify(1,1,n,l,r,x); }else{ change(1,1,n,l,r); } } return 0; }#include<iostream> #include<cstdio> using namespace std; #define int long long inline int read(){ register int x=0,v=1,ch=getchar(); while(!isdigit(ch)){if(ch=='-')v=-1;ch=getchar();} while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();} return x*v; } const int MAX=100005; int n,m,a[MAX]; int op,x; struct Seg{ int sum,mx; }tree[MAX<<2]; inline int Max(int a,int b){ return a>b?a:b; } inline void pushup(int x){ tree[x]=(Seg){tree[x<<1].sum+tree[x<<1|1].sum,Max(tree[x<<1].mx,tree[x<<1|1].mx)}; } void build(int x,int l,int r){ if(l==r){ tree[x]=(Seg){a[l],a[l]}; return ; } register int mid=l+r>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); pushup(x); } void modify(int x,int l,int r,int s,int t,int v){ if(l==r){ tree[x]=(Seg){tree[x].sum%v,tree[x].mx%v}; return ; } register int mid=l+r>>1; if(s<=mid&&tree[x<<1].mx>=v)modify(x<<1,l,mid,s,t,v); if(mid<t&&tree[x<<1|1].mx>=v)modify(x<<1|1,mid+1,r,s,t,v); pushup(x); } void change(int x,int l,int r,int s,int v){ if(l==r){ tree[x]=(Seg){v,v}; return ; } register int mid=l+r>>1; if(s<=mid)change(x<<1,l,mid,s,v); else change(x<<1|1,mid+1,r,s,v); pushup(x); } int query(int x,int l,int r,int s,int t){ if(s<=l&&r<=t)return tree[x].sum; register int res=0,mid=l+r>>1; if(s<=mid)res+=query(x<<1,l,mid,s,t); if(mid<t)res+=query(x<<1|1,mid+1,r,s,t); return res; } int l,r; signed main(){ n=read(),m=read(); for(register int i=1;i<=n;++i)a[i]=read(); build(1,1,n); while(m--){ op=read(); l=read(),r=read(); if(op==1){ printf("%lld\n",query(1,1,n,l,r)); }else if(op==2){ x=read(); modify(1,1,n,l,r,x); }else{ change(1,1,n,l,r); } } return 0; }