#1116 : 计算

链接:
http://hihocoder.com/problemset/problem/1116?sid=615756

时间限制:4000ms
单点时限:1000ms
内存限制:256MB
描述
现在有一个有n个元素的数组a1, a2, …, an。

记f(i, j) = ai * ai+1 * … * aj。

初始时,a1 = a2 = … = an = 0,每次我会修改一个ai的值,你需要实时反馈给我 ∑1 <= i <= j <= n f(i, j)的值 mod 10007。

输入
第一行包含两个数n(1<=n<=100000)和q(1<=q<=500000)。

接下来q行,每行包含两个数i, x,代表我把ai的值改为了x。

输出
分别输出对应的答案,一个答案占一行。

样例输入
5 5
1 1
2 1
3 1
4 1
5 1
样例输出
1
3
6
10
15

这道题很明显的线段树,其中∑1 <= i <= j <= n f(i, j) 可能很多人没有明白,是指连续的在【1,n】的子集之和,我们利用前缀和和后缀和的性质,线段树维护即可。

这里的结构体里面用的是long long 为此还错了几次,我记得BC里面也有一道这样的题,特别坑爹,不过也怪我自己没有考虑周全把,哈哈。

#include<iostream>
using namespace std;
#include<cstdio>
struct note
{
    long long  l,r,d,sum,q,h,j;
} a[404000];

const int mod_=10007;
int n;

void init(int i,int l,int r)
{
    a[i].l=l;
    a[i].r=r;
    a[i].d=0;
    a[i].sum=0;
    if(l==r)
        return ;
    int mid=(a[i].l+a[i].r)>>1;
    init(2*i,l,mid);
    init(2*i+1,mid+1,r);
}
void insertnum(int i,int pos,int d)
{
    if(pos==a[i].l&&pos==a[i].r)
    {
        a[i].d=d%mod_;
        a[i].q=d%mod_;
        a[i].h=d%mod_;
        a[i].j=d%mod_;
        a[i].sum=d%mod_;
        return ;
    }
    int mid=(a[i].l+a[i].r)>>1;
    if(pos<=mid)
        insertnum(2*i,pos,d);
    else
        insertnum(2*i+1,pos,d);
    a[i].j=(a[i<<1].j%mod_*(a[(i<<1)|1].j%mod_))%mod_;
    a[i].q=(a[i<<1].q%mod_+(a[i<<1].j%mod_*a[(i<<1)+1].q%mod_))%mod_;
    a[i].h=(a[i<<1 |1].j%mod_*(a[i<<1].h)%mod_+a[(i<<1)+1].h%mod_)%mod_;
    a[i].sum=(a[i*2+1].sum%mod_+a[i*2].sum%mod_+a[i<<1].h%mod_*a[(i<<1)+1].q%mod_)%mod_;
}

int main()
{
    int t;
    while(cin>>n>>t)
    {
        init(1,1,n);
        while(t--)
        {
            int start,aim;
            scanf("%d%d",&start,&aim);
            insertnum(1,start,aim);
            printf("%d\n",a[1].sum);
        }
    }
    return 0;
}

你可能感兴趣的:(#1116 : 计算)