现在的位置: 首页 > 综合 > 正文

codeforces 266E More Queries to Array 线段树

2012年01月29日 ⁄ 综合 ⁄ 共 2883字 ⁄ 字号 评论关闭

题目大意:给你一串数列,a[1]~a[n]。有两种操作

操作1:", (1 ≤ l ≤ r ≤ n; 0 ≤ x ≤ 109).
表示将区间[l,r]中的数全赋值为x。

操作2:"", (1 ≤ l ≤ r ≤ n; 0 ≤ k ≤ 5).
表示计算的值,取模1000000007后输出。

先给你q个操作,对于每一个操作2,输出对应的值。

 

思路:这道题的关键就在k的范围很小,只有0到5,所以可以考虑建6可线段树分别讨论。对于特定的k,怎么求要求计算的值呢?在做过几次尝试后,我发现很难直接求得(对于不同的 l r,所乘的系数也不同)。既然直接求难度大,那我们不妨分开来求,将所要求的式子拆开来看看。

对于k=0,则相当于求区间和。

对于k=1,原式可化为 a[i]+(1-l);

对于k=2,原式可化为 a[i]^2-2*(l-1)*a[i]+(l-1)^2;

对于k=3,原式可化为 a[i]^3-3*(l-1)*a[i]^2+3*(l-1)^2*a[i]-(l-1)^3;

。。。。。。

我们可以发现对于每个a[i]项,它所乘的系数变得可以确定了(每一个都和(l-1)有关,满足二项式定理)。如果我们在线段树中,对于每一个个区间我们维护,那么对于每一个不同的K(k很小),我们都可以根据上面的式子,展开来分别求,事情到了这一步算法已经基本成型了,剩下的就是实现了。我们首先要建立6个线段树来维护,因为数据量大,所以我们首先将(i^j)%1000000007的值预处理一下,用到的时候在调用即可。对于操作1,我们如果把一个区间的数全赋值为x,则该区间的和则为x*(l^j+(l+1)^j+....(r)^j),对于括号里的值也可以通过预处理来实现,最后注意由于所求的值相当的大,在一些中间运算中可能会爆
long long的,所以一定要在每一个可能越界的地方取模。最后看实现。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 100010
#define mod 1000000007
using namespace std;
#define mid ((t[p].l+t[p].r)>>1)
#define ls (p<<1)
#define rs (ls|1)
long long pow[maxn][6],num[maxn][6];
long long a[maxn];
void init()
{
    long long i;
    memset(num,0,sizeof(num));
    memset(pow,0,sizeof(pow));
    for(i=0;i<=100000;i++)
    {
        int j;
        for(j=0;j<6;j++)
        {
            int k=j;
            long long tmp=1;
            while(k--)
            tmp=(tmp*i)%mod;
            pow[i][j]=tmp;
            if(i!=0)
            num[i][j]=(num[i-1][j]+tmp)%mod;
        }
    }
}
struct tree
{
    int l,r;
    int lazy;
    long long sum[6];
}t[maxn<<2];
void pushup(int p)
{
 int i;
 for(i=0;i<6;i++)
 t[p].sum[i]=(t[ls].sum[i]+t[rs].sum[i])%mod;
}
void update(int p,int val)
{
    t[p].lazy=val;
    int i,l=t[p].l,r=t[p].r;
    for(i=0;i<6;i++)
    t[p].sum[i]=((val*(num[r][i]-num[l-1][i]))%mod+mod)%mod;
}
void pushdown(int p)
{
    if(t[p].lazy!=-1)
    {
        update(ls,t[p].lazy);
        update(rs,t[p].lazy);
        t[p].lazy=-1;
    }
}
void build(int p,int l,int r)
{
    t[p].l=l,t[p].r=r,t[p].lazy=-1;
    if(l==r)
    {
        int i;
        for(i=0;i<6;i++)
        {
            t[p].sum[i]=(pow[l][i]*a[l])%mod;
        }
        return;
    }
    build(ls,l,mid);
    build(rs,mid+1,r); 
    pushup(p);
}
void add(int p,int l,int r,int val)
{
    if(t[p].l==l&&t[p].r==r)
    {
        update(p,val);
        return;
    }
    pushdown(p);
    if(l>mid)
    add(rs,l,r,val);
    else if(r<=mid)
    add(ls,l,r,val);
    else
    {
        add(ls,l,mid,val);
        add(rs,mid+1,r,val);
    }
    pushup(p);
}
long long query(int p,int l,int r,int k)
{
    if(t[p].l==l&&t[p].r==r)
    {
        return t[p].sum[k];
    }
    pushdown(p);
    if(l>mid)
    return query(rs,l,r,k);
    else if(r<=mid)
    return query(ls,l,r,k);
    else
    {
        return (query(ls,l,mid,k)+query(rs,mid+1,r,k))%mod;
    }
}
int l,r;
long long g(int a,int b,int c)
{
    return (query(1,l,r,c)*((a*pow[l-1][b])%mod))%mod;
}
int main()
{
    init();
    int n,q,i;
    scanf("%d%d",&n,&q);
    for(i=1;i<=n;i++)
    scanf("%I64d",&a[i]);
    build(1,1,n);
    char str[2];
    int x;
    while(q--)
    {
        scanf("%s%d%d%d",str,&l,&r,&x);
        if(str[0]=='=')
        {
            add(1,l,r,x);
        }
        else
        {
            long long tmp=0;
            if(x==0)
            {
                tmp=query(1,l,r,0);
            }
            else if(x==1)
            {
                tmp=((g(1,0,1)-g(1,1,0))%mod+mod)%mod;
            }
            else if(x==2)
            {
               tmp=((g(1,0,2)-g(2,1,1)+g(1,2,0))%mod+mod)%mod;
            } 

            else if(x==3)
            {
                tmp=((g(1,0,3)-g(3,1,2)+g(3,2,1)-g(1,3,0))%mod+mod)%mod;
            }
            else if(x==4)
            {
                tmp=((g(1,0,4)-g(4,1,3)+g(6,2,2)-g(4,3,1)+g(1,4,0))%mod+mod)%mod;
            }
            else if(x==5)
            {
                tmp=((g(1,0,5)-g(5,1,4)+g(10,2,3)-g(10,3,2)+g(5,4,1)-g(1,5,0))%mod+mod)%mod;
            }
            printf("%I64d\n",tmp);
        }
    }
    return 0;
}

 

抱歉!评论已关闭.