CDQZ Challenge 4

说在前面:“CDQZ”系列题目数据绝对良心(良苦用心233),提交网址如有需要请私信本蒟蒻。
1004:Challenge 4
查看 提交 统计 提问
总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 262144kB
描述
给一个长为N的数列,有M次操作,每次操作时以下三种之一:

(1)修改数列中的一个数

(2)求数列中某连续一段所有数的两两乘积的和 mod 1000000007

(3)求数列中某连续一段所有相邻两数乘积的和 mod 1000000007

输入
第一行两个正整数N和M。
第二行N的整数表示这个数列。
接下来M行,每行开头是一个字符,若该字符为’M’,则表示一个修改操作,接下来两个整数x和y,表示把x位置的值修改为y;若该字符为’Q’,则表示一个询问操作,接下来两个整数x和y,表示对[x,y]区间做2号询问;若该字符为’A’,则表示一个询问操作,接下来两个整数x和y,表示对[x,y]区间做3号询问。
输出
对每一个询问操作单独输出一行,表示答案。
样例输入
5 5
1 2 3 4 5
Q 1 5
A 1 5
M 2 7
Q 1 5
A 1 5
样例输出
85
40
150
60
提示
1<=N<=10^5,1<=M<=10^5,输入保证合法,且所有整数可用带符号32位整型存储。

题解:线段树操作即可,在进行第一种询问(Q)时,由于同时需要区间的两个信息:1.区间和2.所有数两两乘积之和,所以可以写个pair,也可以单独写一个query_sum()函数询问区间和,前一个是O(nlog(n))的,后者目测应该是O(nlog(n)log(n))的,所以机智的本蒟蒻选择了写pair。

注意两点:1.凡是要乘爆int的,即使会取余,也要开longlong或者转longlong 2.有负数取余一定要再加一次再模一次。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<utility>
#define root 1,1,n
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
typedef long long ll;
const int MAXN=1e5+2;
const ll MOD=1e9+7;
int n,m;
ll sum[MAXN<<2],sa[MAXN<<2],sb[MAXN<<2],num[MAXN];
typedef pair<ll,ll> pa;
inline int read() {
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
inline void pushup(int rt,int mid) {
    int l=rt<<1,r=rt<<1|1;
    sum[rt]=(sum[l]+sum[r])%MOD;
    sa[rt]=((sa[l]+sa[r])%MOD+sum[l]*sum[r]%MOD)%MOD;
    sb[rt]=((sb[l]+sb[r])%MOD+num[mid]*num[mid+1]%MOD)%MOD;
}
void build(int rt,int l,int r) {
    if (l==r) {
        sum[rt]=num[l],sa[rt]=sb[rt]=(ll)0;
        return ;
    }
    int mid=(l+r)>>1;
    build(lson),
    build(rson),
    pushup(rt,mid);
}
void modify(int rt,int l,int r,int pos,ll val) {
    if (l==r) {
        sum[rt]=val;
        return ;
    }
    int mid=(l+r)>>1;
    if (pos<=mid) modify(lson,pos,val);
    else modify(rson,pos,val);
    pushup(rt,mid);
}
pa qa(int rt,int l,int r,int L,int R) {//sa,sum
    if (L<=l&&r<=R) return pa(sa[rt],sum[rt]);
    int mid=(l+r)>>1;
    if (R<=mid) return qa(lson,L,R);
    else if (mid<L) return qa(rson,L,R);
    else {
        pa t1=qa(lson,L,mid),t2=qa(rson,mid+1,R);
        return pa(((t1.first+t2.first)%MOD+(t1.second*t2.second)%MOD)%MOD,(t1.second+t2.second)%MOD);
    }
}
pa qb(int rt,int l,int r,int L,int R) {//sb,sum
    if (L<=l&&r<=R) return pa(sb[rt],sum[rt]);
    int mid=(l+r)>>1;
    if (R<=mid) return qb(lson,L,R);
    else if (mid<L) return qb(rson,L,R);
    else {
        pa t1=qb(lson,L,mid),t2=qb(rson,mid+1,R);
        return pa(((t1.first+t2.first)%MOD+(num[mid]*num[mid+1])%MOD)%MOD,(t1.second+t2.second)%MOD);
    }
}
int main() {
//  freopen("Challenge 4.in","r",stdin);
    n=read(),m=read();
    for (register int i=1;i<=n;++i) num[i]=(ll)read();
    build(root);
    for (register int i=1;i<=m;++i) {
        char ss;
        while (!isalpha(ss=getchar()));
        if (ss=='M') {
            int pos=read();
            num[pos]=(ll)read();//!!!
            modify(root,pos,num[pos]);
        }
        else if (ss=='Q') {
            int L=read(),R=read();
            printf("%lld\n",(qa(root,L,R).first+MOD)%MOD);
        }
        else {
            int L=read(),R=read();
            printf("%lld\n",(qb(root,L,R).first+MOD)%MOD);
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值