描述
给出一个长为n的序列
编号 | 输入格式 | 含义 |
---|---|---|
1 l r | 求区间 的和 | |
2 | 2 l r | 求区间 的最大值 |
3 | 3 l r | 求区间 的最小值 |
4 | 4 l r x | 将区间 内的所有数加上 x |
5 | 5 i x | 将第 个数按位异或 x |
6 | 6 l r | 求区间 内所有数的平均值(保留两位小数) |
7 | 7 l r | 将区间 内的所有数都变为原来的相反数 |
8 | 8 l r x | 将区间 内的所有数赋值为 x |
9 | 9 l r | 求区间 内所有数的平方和 |
对于操作 1 和 9,输出要对 取模。
输入
第一行两个正整数 n,m 表示序列长度和操作个数。
之后的一行n 个整数,表示初始序列。
之后的 m 行,每行三个或四个正整数,表示一次操作。
输出
对于每一个操作 1、2、3、6、9,输出一行一个整数或小数,表示答案。
样例输入
5 4
1 2 3 4 5
4 1 2 3
2 4 5
8 2 3 4
9 3 4
样例输出
5
32
提示
N,M<=100000
对于100%的数据,区间和不会爆long long
这线段树真有(ma)趣(nong)啊。。。
调了半天发现把一个模号打成了乘号233,其实代码还是比较短的(也就3kb出头而已。。。)
如果考试考这题估计也只有打暴力的份了。。。
我的写法是pushdown时先传覆盖标记,再传取相反数标记,最后传区间加标记。
代码:
#include<bits/stdc++.h>
#define N 500005
#define ll long long
#define mod 1000000007
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
using namespace std;
struct Node{int l,r,mx,mn;ll sum,sec,rev,cov,add;bool flag;}T[N<<2];
int n,m;
ll a[N];
inline ll read(){
ll ans=0,w=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans*w;
}
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
inline void pushup(int p){
T[p].sum=T[lc].sum+T[rc].sum,T[p].sec=(T[lc].sec+T[rc].sec)%mod;
T[p].mx=max(T[lc].mx,T[rc].mx),T[p].mn=min(T[lc].mn,T[rc].mn);
}
inline void pushset(int p,ll v){
T[p].flag=true,T[p].cov=T[p].mx=T[p].mn=v,T[p].add=T[p].rev=0;
T[p].sum=(T[p].r-T[p].l+1)*v,T[p].sec=v*v%mod*(T[p].r-T[p].l+1)%mod;
}
inline void pushrev(int p){T[p].rev^=1,T[p].add=-T[p].add;T[p].sum=-T[p].sum,T[p].mx=-T[p].mx,T[p].mn=-T[p].mn,swap(T[p].mx,T[p].mn);}
inline void pushadd(int p,ll v){
T[p].sec=(T[p].sec+v*v%mod*(T[p].r-T[p].l+1)%mod+T[p].sum%mod*2*v%mod+mod)%mod;
T[p].sum+=v*(T[p].r-T[p].l+1),T[p].mx+=v,T[p].mn+=v,T[p].add+=v;
}
inline void pushdown(int p){
if(T[p].flag)pushset(lc,T[p].cov),pushset(rc,T[p].cov),T[p].flag=false;
if(T[p].rev)pushrev(lc),pushrev(rc),T[p].rev=0;
if(T[p].add)pushadd(lc,T[p].add),pushadd(rc,T[p].add),T[p].add=0;
}
inline void build(int p,int l,int r){
T[p].l=l,T[p].r=r,T[p].flag=false,T[p].rev=0,T[p].add=0;
if(l==r){T[p].sum=T[p].mx=T[p].mn=a[l],T[p].sec=a[l]*a[l]%mod;return;}
build(lc,l,mid),build(rc,mid+1,r),pushup(p);
}
inline void update(int p,int ql,int qr,ll v,int op){
if(ql>T[p].r||qr<T[p].l)return;
if(ql<=T[p].l&&T[p].r<=qr)return op==1?pushadd(p,v):(op==2?pushrev(p):pushset(p,v));
pushdown(p);
if(qr<=mid)update(lc,ql,qr,v,op);
else if(ql>mid)update(rc,ql,qr,v,op);
else update(lc,ql,mid,v,op),update(rc,mid+1,qr,v,op);
pushup(p);
}
inline ll solve(ll a,ll b,int op){return op<3?(op==1?a+b:(a+b)%mod):(op==3?max(a,b):min(a,b));}
inline ll query(int p,int ql,int qr,int op){
if(ql>T[p].r||qr<T[p].l)return op<3?0:(op==3?-9223372036854775807:9223372036854775807);
if(ql<=T[p].l&&T[p].r<=qr)return op<3?(op==1?T[p].sum:T[p].sec):(op==3?T[p].mx:T[p].mn);
pushdown(p);
if(qr<=mid)return query(lc,ql,qr,op);
if(ql>mid)return query(rc,ql,qr,op);
return solve(query(lc,ql,mid,op),query(rc,mid+1,qr,op),op);
}
inline void modify(int p,int k,ll x){
if(T[p].l==T[p].r){T[p].sum^=x,T[p].mx^=x,T[p].mn^=x,T[p].sec=T[p].sum%mod*T[p].sum%mod;return;}
pushdown(p);
if(k<=mid)modify(lc,k,x);
else modify(rc,k,x);
pushup(p);
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i)a[i]=read();
build(1,1,n);
while(m--){
int op=read();
ll l=read(),r=read();
if(op==1)printf("%lld\n",(query(1,l,r,1)%mod+mod)%mod);
else if(op==2)printf("%lld\n",query(1,l,r,3));
else if(op==3)printf("%lld\n",query(1,l,r,4));
else if(op==4){ll x=read();update(1,l,r,x,1);}
else if(op==5)modify(1,l,r);
else if(op==6)printf("%.2lf\n",query(1,l,r,1)*1.0/(r-l+1));
else if(op==7)update(1,l,r,0,2);
else if(op==8){ll x=read();update(1,l,r,x,3);}
else printf("%lld\n",query(1,l,r,2));
}
return 0;
}