HDU 4578 Transformation --线段树,好题

题意: 给一个序列,初始全为0,然后有4种操作:

1. 给区间[L,R]所有值+c

2.给区间[L,R]所有值乘c

3.设置区间[L,R]所有值为c

4.查询[L,R]的p次方和(1<=p<=3)

解法: 线段树,维护三个标记,addmark,mulmark,setmark分别表示3种更新,然后p[1],p[2],p[3]分别表示该节点的1,2,3次方和。标记传递顺序setmark一定是第一个,因为setmark可以使mulmark,addmark都失效还原,mulmark和addmark的顺序倒是无所谓。

这题写了半个比赛时间,写的很迷,还是没写出来, 后来看了别人写的,才知道自己很多地方都没更新好甚至没更新。这题算是一道线段树的综合题了,混合了几种常见的更新,对线段树的整体把握很有帮助。

比如:

1.如果setmark有值,那么addmark,mulmark全部要还原。

2.如果mulmark有值,那么addmark也要更新,更新为addmark*mulmark

就是这两点一直没考虑到,WA了好久。

在addmark下传过程中更新p[1],p[2],p[3]的方法如下:

比如 a^3 -> (a+c)^3 的过程:  (a+c)^3 = a^3 + c^3 + 3a*c^2 + 3*a^2*c, a是变量, 所以提取出c,那么p[3]可以由p[1],p[2]推出,p[2]可以由p[1]推出。

即 p[3] = p[3] + c^3 + 3*c^2*p[1] + 3*c*p[2] . 

p[2]同理可以由p[1]推出。

然后每次都做一下pushdown,就可以得出正确答案。

当时像优化一下,少做几次pushdown,即这次的操作类型与上次一样就不pushdown,结果那样就会出现问题,还不如每次都pushdown呢。

代码:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <cmath>

#include <algorithm>

#define Mod 10007

#define SMod 10007

using namespace std;

#define N 100017



struct node{

    int p[4];

    int setmark,addmark,mulmark;

}tree[4*N];



void pushup(int rt){

    for(int i=1;i<=3;i++) tree[rt].p[i] = (tree[2*rt].p[i] + tree[2*rt+1].p[i])%SMod;

}



void pushdown(int l,int r,int rt)

{

    int mid = (l+r)/2;

    if(tree[rt].setmark)

    {

        int mk = tree[rt].setmark;

        tree[rt<<1].setmark = tree[rt<<1|1].setmark = mk;

        tree[rt<<1].addmark = tree[rt<<1|1].addmark = 0;

        tree[rt<<1].mulmark = tree[rt<<1|1].mulmark = 1;



        tree[rt<<1].p[1] = (mid-l+1)%Mod*mk%SMod;

        tree[rt<<1|1].p[1] = (r-mid)%Mod*mk%SMod;



        tree[rt<<1].p[2] = (mid-l+1)%Mod*mk%SMod*mk%SMod;

        tree[rt<<1|1].p[2] = (r-mid)%Mod*mk%SMod*mk%SMod;



        tree[rt<<1].p[3] = (mid-l+1)%Mod*mk%SMod*mk%SMod*mk%SMod;

        tree[rt<<1|1].p[3] = (r-mid)%Mod*mk%SMod*mk%SMod*mk%SMod;

        tree[rt].setmark = 0;

    }

    if(tree[rt].mulmark != 1)

    {

        int mk = tree[rt].mulmark;

        tree[rt<<1].mulmark *= mk, tree[rt<<1].mulmark%=SMod;

        tree[rt<<1|1].mulmark *= mk, tree[rt<<1|1].mulmark%=SMod;



        tree[rt<<1].addmark = tree[rt<<1].addmark%SMod*mk%SMod;

        tree[rt<<1|1].addmark = tree[rt<<1|1].addmark%SMod*mk%SMod;



        tree[rt<<1].p[1] = tree[rt<<1].p[1]%Mod*mk%SMod;

        tree[rt<<1|1].p[1] = tree[rt<<1|1].p[1]%Mod*mk%SMod;



        tree[rt<<1].p[2] = tree[rt<<1].p[2]%Mod*mk%SMod*mk%SMod;

        tree[rt<<1|1].p[2] = tree[rt<<1|1].p[2]%Mod*mk%SMod*mk%SMod;



        tree[rt<<1].p[3] = tree[rt<<1].p[3]%Mod*mk%SMod*mk%SMod*mk%SMod;

        tree[rt<<1|1].p[3] = tree[rt<<1|1].p[3]%Mod*mk%SMod*mk%SMod*mk%SMod;

        tree[rt].mulmark = 1;

    }

    if(tree[rt].addmark)

    {

        int mk = tree[rt].addmark;

        tree[rt<<1].addmark += mk, tree[rt<<1].addmark%SMod;

        tree[rt<<1|1].addmark += mk, tree[rt<<1|1].addmark%SMod;



        tree[rt<<1].p[3] = (tree[rt<<1].p[3]%Mod + (mid-l+1)%Mod*mk%SMod*mk%SMod*mk%SMod + 3*mk%Mod*tree[rt<<1].p[2]%SMod + 3*mk%SMod*mk%SMod*tree[rt<<1].p[1]%SMod)%SMod;

        tree[rt<<1|1].p[3] = (tree[rt<<1|1].p[3]%Mod + (r-mid)%Mod*mk%SMod*mk%SMod*mk%SMod + 3*mk%Mod*tree[rt<<1|1].p[2]%SMod + 3*mk%SMod*mk%SMod*tree[rt<<1|1].p[1]%SMod)%SMod;



        tree[rt<<1].p[2] = (tree[rt<<1].p[2]%Mod + (mid-l+1)%Mod*mk%SMod*mk%SMod + 2*mk%Mod*tree[rt<<1].p[1]%SMod)%SMod;

        tree[rt<<1|1].p[2] = (tree[rt<<1|1].p[2]%Mod + (r-mid)%Mod*mk%SMod*mk%SMod + 2*mk%Mod*tree[rt<<1|1].p[1]%SMod)%SMod;



        tree[rt<<1].p[1] = (tree[rt<<1].p[1]%Mod + (mid-l+1)%Mod*mk%SMod)%SMod;

        tree[rt<<1|1].p[1] = (tree[rt<<1|1].p[1]%Mod + (r-mid)%Mod*mk%SMod)%SMod;

        tree[rt].addmark = 0;

    }

}



void build(int l,int r,int rt)

{

    tree[rt].setmark = tree[rt].addmark = 0;

    tree[rt].mulmark = 1;

    memset(tree[rt].p,0,sizeof(tree[rt].p));

    if(l == r) return;

    int mid = (l+r)/2;

    build(l,mid,rt<<1);

    build(mid+1,r,rt<<1|1);

}



void update(int l,int r,int aa,int bb,int tag,int val,int rt)  //tag = 3 : set  2:mul 1: add

{

    if(aa <= l && bb >= r)

    {

        if(tag == 3)

        {

            tree[rt].p[1] = (r-l+1)%Mod*val%SMod;

            tree[rt].p[2] = (r-l+1)%Mod*val%SMod*val%SMod;

            tree[rt].p[3] = (r-l+1)%Mod*val%SMod*val%SMod*val%SMod;

            tree[rt].setmark = val;

            tree[rt].addmark = 0;

            tree[rt].mulmark = 1;

        }

        else if(tag == 2)

        {

            tree[rt].p[1] = tree[rt].p[1]%SMod*val%SMod;

            tree[rt].p[2] = tree[rt].p[2]%SMod*val%SMod*val%SMod;

            tree[rt].p[3] = tree[rt].p[3]%SMod*val%SMod*val%SMod*val%SMod;

            tree[rt].mulmark = tree[rt].mulmark%SMod*val%SMod;

            tree[rt].addmark = tree[rt].addmark%SMod*val%SMod;

        }

        else if(tag == 1)

        {

            tree[rt].p[3] = (tree[rt].p[3]%SMod + (r-l+1)%SMod*val%SMod*val%SMod*val%SMod + 3*val%SMod*tree[rt].p[2]%SMod + 3*val%SMod*val%SMod*tree[rt].p[1]%SMod)%SMod;

            tree[rt].p[2] = (tree[rt].p[2]%SMod + (r-l+1)%SMod*val%SMod*val%SMod + 2*val%SMod*tree[rt].p[1]%SMod)%SMod;

            tree[rt].p[1] = (tree[rt].p[1]%SMod + (r-l+1)%SMod*val%SMod)%SMod;

            tree[rt].addmark = (tree[rt].addmark+val)%SMod;

        }

        return;

    }

    int mid = (l+r)/2;

    pushdown(l,r,rt);

    if(aa <= mid) update(l,mid,aa,bb,tag,val,rt<<1);

    if(bb > mid)  update(mid+1,r,aa,bb,tag,val,rt<<1|1);

    pushup(rt);

}



int query(int l,int r,int aa,int bb,int i,int rt)

{

    if(aa > r || bb < l) return 0;

    if(aa <= l && bb >= r)

        return tree[rt].p[i];

    pushdown(l,r,rt);

    int res = 0;

    int mid = (l+r)/2;

    return (query(l,mid,aa,bb,i,rt<<1)%SMod+query(mid+1,r,aa,bb,i,rt<<1|1)%SMod)%SMod;

}



int main()

{

    int n,m,i,j,op,x,y,c;

    while(scanf("%d%d",&n,&m)!=EOF && n+m)

    {

        build(1,n,1);

        while(m--)

        {

            scanf("%d%d%d%d",&op,&x,&y,&c);

            if(op != 4) update(1,n,x,y,op,c,1);

            else        printf("%d\n",query(1,n,x,y,c,1)%SMod);

        }

    }

    return 0;

}
View Code

你可能感兴趣的:(transform)