Fork me on GitHub

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
posted @ 2014-11-20 22:32  whatbeg  阅读(329)  评论(0编辑  收藏  举报