• HDU 4578 Transformation (线段树区间多种更新)


    http://acm.hdu.edu.cn/showproblem.php?pid=4578

    题目大意:对于一个给定序列,序列内所有数的初始值为0,有4种操作。1:区间(x, y)内的所有数字全部加上C;2:区间(x, y)内所有数字全部乘C; 3:区间(x, y)内的所有数字全部重置为C;

    4:输出区间(x, y)内所有数字的P次方的和。由于题目为多实例(至少10组样例),故很耿直的更新到叶子节点明显会TLE;因此需优化。可发现题目所有操作都是对区间进行,因此只需要更新

    到区间内数字相同即可。再者注意可进行状态压缩,不需要的累加和累乘只标记即可,需要此部分时再往下更新;更新时先更新3,因为3会覆盖掉1和2;之后再进行累乘,因为累乘影响累加,累

    加不影响累乘。注意细节即可。

    ///至少10组样例,则八秒实际上不多,需优化。
    ///由于所有操作都是对区间进行,故数字保存情况为
    ///分区间相同,因此只需要操作到区间数字相同时即可,不必处理到最下面的叶子节点
    #include <stdio.h>
    #include <algorithm>
    using namespace std;
    #define N 110000
    #define mod 10007
    #define lson rt<<1
    #define rson rt<<1|1
    struct tree
    {
        int l, r, add, mul, op, num;
        ///add记录累加的数,mul记录累乘的数,op记录操作的状态
        ///op为1表示区间内数字相同,op为0表示区间内数字不同,需向下
        ///继续进行操作,op为2表示区间被重新赋值,需向下更新(操作3)。
        int len()
        {
            return r-l+1;
        }
    }a[N<<2];
    void build(int l, int r, int rt)///初始化
    {
        a[rt].l = l;
        a[rt].r = r;
        a[rt].mul = a[rt].op = 1;
        a[rt].add = a[rt].num = 0;
        if(l==r)return ;
        int mid = (l+r)/2;
        build(l, mid, lson);
        build(mid+1, r, rson);
    }
    void Change(int rt, int op, int k)
    {
        if(op==3)///重新赋值,即再次初始化
        {
            a[rt].num = k%mod;
            a[rt].mul = 1;
            a[rt].add = 0;
            a[rt].op = 2;///重新赋值后子区间所有都重新覆盖
        }
        else if(op==2)
        {
            (a[rt].add *= k) %= mod;
            (a[rt].mul *= k) %= mod;
            (a[rt].num *= k) %= mod;
        }
        else
        {
            (a[rt].add += k) %= mod;
            (a[rt].num += k) %= mod;
        }
    }
    
    void Up(int rt)
    {
        if(a[lson].op && a[rson].op)///若子区间为同数字区间且两子区间数字相同,
        if(a[lson].num == a[rson].num)///则可向上合并给父区间
        {
            a[rt].num = a[lson].num;
            a[rt].op = 1;
        }
    }
    
    void Down(int rt)///向下的状态压缩,若不需此区间作答此区间暂时储存;
    {                ///若需此区间作答则向下更新一层直到叶子节点
        if(a[rt].l != a[rt].r)
        {
            if(a[rt].op==2)
            {
                a[lson].num = a[rson].num = a[rt].num;
    
                a[lson].op = a[rson].op = 2;
                a[lson].add = a[rson].add = 0;
                a[lson].mul = a[rson].mul = 1;
    
                a[rt].add = 0;
                a[rt].mul = 1;
                a[rt].op = 1;
            }
    
            if(a[rt].mul>1)///注意此处,先更新乘法,因为累乘会影响累加的状态
            {
                (a[lson].num *= a[rt].mul) %= mod;
                (a[lson].add *= a[rt].mul) %= mod;
                (a[lson].mul *= a[rt].mul) %= mod;
    
                (a[rson].num *= a[rt].mul) %= mod;
                (a[rson].add *= a[rt].mul) %= mod;
                (a[rson].mul *= a[rt].mul) %= mod;
    
                a[rt].mul = 1;
            }
    
            if(a[rt].add)
            {
                (a[lson].num += a[rt].add) %= mod;
                (a[lson].add += a[rt].add) %= mod;
    
                (a[rson].num += a[rt].add) %= mod;
                (a[rson].add += a[rt].add) %= mod;
    
                a[rt].add = 0;
            }
        }
    }
    void Update(int rt, int op, int l, int r, int k)
    {
        if(a[rt].l==l && a[rt].r==r && a[rt].op)///找到数字相同区间
        {
            Change(rt, op, k);///执行操作
            return ;
        }
    
        Down(rt);
        a[rt].op = 0;///假设默认区间数字已改变,标记为不同。
    
        int mid = (a[rt].l + a[rt].r)/2;
        if(mid>=r)Update(lson, op, l, r, k);
        else if(mid<l)Update(rson, op, l, r, k);
        else
        {
            Update(lson, op, l, mid, k);
            Update(rson, op, mid+1, r, k);
        }
    
        Up(rt);///执行操作后向上回溯,用已得到的子区间反馈负区间的状态
    }
    int Query(int rt, int l, int r, int p)
    {
        if(a[rt].l==l && a[rt].r==r && a[rt].op)///找到同数字区间即可计算
        {
            int ans = 1;
            for(int i=1; i<=p; i++)///一个p次方
                (ans *= a[rt].num) %= mod;
            ans = (ans * a[rt].len())%mod; ///区间内所有p次方
            return ans;
        }
    
        Down(rt);
    
        int mid = (a[rt].l + a[rt].r)/2;
    
        if(mid>=r)return Query(lson, l, r, p);
        else if(mid<l)return Query(rson, l, r, p);
        else
        {
            int lans = Query(lson, l, mid, p);
            int rans = Query(rson, mid+1, r, p);
            return (lans+rans)%mod;
        }
    }
    int main()
    {
        int n, m;
        while(scanf("%d %d", &n, &m), m+n)
        {
            build(1, n, 1);
            int op, l, r, k;
            while(m--)
            {
                scanf("%d %d %d %d", &op, &l, &r, &k);
                if(op!=4)Update(1, op, l, r, k);///只要不为4都是更新操作
                else printf("%d
    ", Query(1, l, r, k));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    学习笔记: js插件 —— fullPage.js (页面全屏滚动)
    学习笔记: js插件 —— SuperSlide 2 (轮播图插件,PC用)
    学习笔记:jqchart
    学习笔记:Highcharts
    js: 字符集
    代码:PC HTML——图片列表
    教程:给初学的几个小例子(待补充)
    代码: html 页面小效果 (集合,待补充)
    MongoDB
    mongodb权限机制以及扩展
  • 原文地址:https://www.cnblogs.com/zznulw/p/5665214.html
Copyright © 2020-2023  润新知