hdu4578 Transformation 解题报告

题意:给一个序列a[i],初始值均为0,,定义4种操作:

1.将某一段a[i]都加上val

2.将某一段a[i]都乘上val

3.将某一段a[i]都变成val

4.询问某一段的和,平方和,立方和

        分析:

很容易想到是线段树处理的题目,并且要用到Lazy思想,一开始的想法是我们可以用sum1,sum2,sum3来维护某段的和,平方和,立方和。然后把每个结点做一个标记(对应操作1,2,3),如果该结点之前存在标记就push_down,但是分析就知道,只要做标记需要递归的push_down(即如果push_down的子树也存在标记就要先处理子树的标记,先将子树push_down),显然效率不高。

        再次分析可知,我们可以把每个结点都表示为ax+b的形式,如果是操作1,就是在把b->b+val,操作2就是a->a*val  b->b*val,操作3就是a->1,b->0,同时记录下变成的val值c->val,这样的话,我们push_down时就只要push一层即可无需递归,因为可以将子树的ax+b和父亲的ax+b相结合

题目代码有点繁杂,写得时候要细心,特别是push_down的时候,对拍了很多次才A掉。。。

c++代码:

#include<cstdio>
const int MAX = 100020;
const int N = 10007;
int ans;
typedef struct
{
    int left,right;
    int a,b;                //ax+b形式
    int c;                  //记录操作3的值
    int num;                 //num = (r-l+1)
    int sum1,sum2,sum3;     //分别存1次和,2次和,3次和
} NODE;
NODE tree[3*MAX];

void buildtree(int i,int l,int r)
{
    tree[i].left = l;
    tree[i].right = r;
    tree[i].a = 1;
    tree[i].b = tree[i].c = 0;
    tree[i].num = (r-l+1);
    tree[i].sum1 = tree[i].sum2 = tree[i].sum3 = 0;
    if (r - l > 0)
    {
        int mid = (l+r)>>1;
        buildtree(i<<1,l,mid);
        buildtree(i<<1|1,mid+1,r);
    }
}
inline void calc(int i,int flag,int c)
{
    if (flag == 1)
    {
        tree[i].b = (tree[i].b+c)%N;
        tree[i].sum3 = (tree[i].sum3 + tree[i].num*c%N*c%N*c%N+3*tree[i].sum1%N*c%N*c%N+3*tree[i].sum2%N*c%N)%N;
        tree[i].sum2 = (tree[i].sum2 + tree[i].num*c%N*c%N+2*c%N*tree[i].sum1%N)%N;
        tree[i].sum1 = (tree[i].sum1 + tree[i].num*c)%N;
    }
    else if (flag == 2)
    {
        tree[i].a = (tree[i].a*c)%N;
        tree[i].b = (tree[i].b*c)%N;
        tree[i].sum3 = c*c%N*c%N*tree[i].sum3%N;
        tree[i].sum2 = c*c%N*tree[i].sum2%N;
        tree[i].sum1 = c*tree[i].sum1%N;
    }
    else if (flag == 3)
    {
        tree[i].a = 1;
        tree[i].b = 0;
        tree[i].c = c;
        tree[i].sum3 = tree[i].num*c%N*c%N*c%N;
        tree[i].sum2 = tree[i].num*c%N*c%N;
        tree[i].sum1 = tree[i].num*c%N;
    }

}
void down(int i)
{
    int zuo,you,a,b,c;
    if (tree[i].num == 1) return;
    zuo = i<<1;
    you = i<<1|1;
    a = tree[i].a;
    c = tree[i].c;
    b = tree[i].b;
    if (c != 0)
    {
        tree[you].a = tree[zuo].a = a;
        tree[you].b = tree[zuo].b = b;
        tree[zuo].c = c;
        tree[zuo].sum3 = tree[zuo].num*(a*c%N+b)%N*(a*c%N+b)%N*(a*c%N+b)%N;
        tree[zuo].sum2 = tree[zuo].num*(a*c%N+b)%N*(a*c%N+b)%N;
        tree[zuo].sum1 = tree[zuo].num*(a*c%N+b)%N;
        tree[you].c = c;
        tree[you].sum3 = tree[you].num*(a*c%N+b)%N*(a*c%N+b)%N*(a*c%N+b)%N;
        tree[you].sum2 = tree[you].num*(a*c%N+b)%N*(a*c%N+b)%N;
        tree[you].sum1 = tree[you].num*(a*c%N+b)%N;
    }
    else
    {
        tree[zuo].a = a * tree[zuo].a%N;
        tree[zuo].b = (b + a*tree[zuo].b%N)%N;
        tree[zuo].sum3 = (a*a%N*a%N*tree[zuo].sum3%N+3*a%N*a%N*b%N*tree[zuo].sum2%N+
                        3*a%N*b%N*b%N*tree[zuo].sum1%N+b*b%N*b%N*tree[zuo].num%N)%N;
        tree[zuo].sum2 = (a*a%N*tree[zuo].sum2%N+2*a%N*b%N*tree[zuo].sum1%N+b*b%N*tree[zuo].num%N)%N;
        tree[zuo].sum1 = (a*tree[zuo].sum1%N+tree[zuo].num*b%N)%N;

        tree[you].a = a * tree[you].a%N;
        tree[you].b = (b + a*tree[you].b%N)%N;
        tree[you].sum3 = (a*a%N*a%N*tree[you].sum3%N+3*a%N*a%N*b%N*tree[you].sum2%N+
                        3*a%N*b%N*b%N*tree[you].sum1%N+b*b%N*b%N*tree[you].num%N)%N;
        tree[you].sum2 = (a*a%N*tree[you].sum2%N+2*a%N*b%N*tree[you].sum1%N+b*b%N*tree[you].num%N)%N;
        tree[you].sum1 = (a*tree[you].sum1%N+tree[you].num*b%N)%N;
    }
}
void update(int i,int flag,int l,int r,int c)
{
    if (tree[i].left == l && tree[i].right == r)
    {
        calc(i,flag,c);
        return;
    }
    else
    {
        down(i);
        tree[i].a = 1;
        tree[i].b = 0;
        tree[i].c = 0;
        int mid = (tree[i].left+tree[i].right)>>1;
        if (r <= mid)
            update(i<<1,flag,l,r,c);
        else if (l > mid)
            update(i<<1|1,flag,l,r,c);
        else
        {
            update(i<<1,flag,l,mid,c);
            update(i<<1|1,flag,mid+1,r,c);
        }
        tree[i].sum1 = (tree[i<<1].sum1 + tree[i<<1|1].sum1)%N;
        tree[i].sum2 = (tree[i<<1].sum2 + tree[i<<1|1].sum2)%N;
        tree[i].sum3 = (tree[i<<1].sum3 + tree[i<<1|1].sum3)%N;
    }
}
void find(int i,int c,int l,int r)
{
    if (tree[i].left == l && tree[i].right == r)
    {
        if (c == 1) ans = ans+tree[i].sum1;
        else if (c == 2) ans = ans + tree[i].sum2;
        else if (c == 3) ans = ans + tree[i].sum3;
        ans = ans % N;
        return;
    }
    down(i);
    tree[i].a = 1;
    tree[i].b = 0;
    tree[i].c = 0;
    int mid = (tree[i].left+tree[i].right)>>1;
    if (r <= mid)
        find(i<<1,c,l,r);
    else if (l > mid)
        find(i<<1|1,c,l,r);
    else
    {
        find(i<<1,c,l,mid);
        find(i<<1|1,c,mid+1,r);
    }
}
int main()
{
    int n,m,i,x,y,c,flag;
    while(scanf("%d%d",&n,&m) == 2)
    {
        if (n+m==0) break;
        buildtree(1,1,n);
        for (i = 1; i <= m; i++)
        {
            scanf("%d%d%d%d",&flag,&x,&y,&c);
            if(flag == 4)
            {
                ans = 0;
                find(1,c,x,y);
                printf("%d\n",ans);
            }
            else
                update(1,flag,x,y,c%N);
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值