zoukankan      html  css  js  c++  java
  • HDU 4578 线段树玄学算法?

    Transformation

    题目链接

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

    Problem Description

    Yuanfang is puzzled with the question below:
    There are n integers, a1, a2, …, an. The initial values of them are 0. There are four kinds of operations.
    Operation 1: Add c to each number between ax and ay inclusive. In other words, do transformation ak<---ak+c, k = x,x+1,…,y.
    Operation 2: Multiply c to each number between ax and ay inclusive. In other words, do transformation ak<---ak×c, k = x,x+1,…,y.
    Operation 3: Change the numbers between ax and ay to c, inclusive. In other words, do transformation ak<---c, k = x,x+1,…,y.
    Operation 4: Get the sum of p power among the numbers between ax and ay inclusive. In other words, get the result of axp+ax+1p+…+ay p.
    Yuanfang has no idea of how to do it. So he wants to ask you to help him.

    Input

    There are no more than 10 test cases.
    For each case, the first line contains two numbers n and m, meaning that there are n integers and m operations. 1 <= n, m <= 100,000.
    Each the following m lines contains an operation. Operation 1 to 3 is in this format: "1 x y c" or "2 x y c" or "3 x y c". Operation 4 is in this format: "4 x y p". (1 <= x <= y <= n, 1 <= c <= 10,000, 1 <= p <= 3)
    The input ends with 0 0.

    Output

    For each operation 4, output a single integer in one line representing the result. The answer may be quite large. You just need to calculate the remainder of the answer when divided by 10007.

    Sample Input

        5 5
        3 3 5 7
        1 2 4 4
        4 1 5 2
        2 2 5 8
        4 3 5 3
        0 0
    

    Sample Output

        307
        7489
    

    题意

    给你一个序列,支持四种操作

    1.区间加法

    2.区间乘法

    3.区间减法

    4.求和,平方和,立方和 即(large sum_{i=l}^{r}{a_i^p}(1le ple 3))

    题解

    一开始看到这道题,觉得可以用数学公式搞搞,搞了半天确实搞出了个公式,用sum1,sum2,sum3分别存和,平方和,立方和,然后合并的时候再搞

    搞。但是感觉很麻烦,于是先上网查了查正解是不是有什么巧妙的方法。但是看完网上题解,我才发现都是用的玄学复杂度。

    于是我就愉快地也跟着各位大佬一样玄学操作啦。

    具体操作:还是用线段树,遇到一段连续相同的区间就可以马上得到答案,其余部分直接暴力就行,我寻思着只要先把每个数都变得不一样然后求所有数的立方和,直接就暴了(别想那么多,这题纯属娱乐)。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define INF 0x7f7f7f7f
    #define N 100050
    #define mo 10007
    ll n,m;
    struct Node{ll l,r,lazy;};
    struct segmentTree
    {
        Node tr[N<<2];
        void push_up(ll x);
        void push_down(ll x);
        void bt(ll x,ll l,ll r);
        void add(ll x,ll l,ll r,ll tt);
        void multiply(ll x,ll l,ll r,ll tt);
        void cover(ll x,ll l,ll r,ll tt);
        ll query(ll x,ll l,ll r,ll tt);
    }seg;
    template<typename T>void read(T&x)
    {
        ll k=0; char c=getchar();
        x=0;
        while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
        if (c==EOF)exit(0);
        while(isdigit(c))x=x*10+c-'0',c=getchar();
        x=k?-x:x;
    }
    void read_char(char &c)
    {while(!isalpha(c=getchar())&&c!=EOF);}
    void segmentTree::push_up(ll x)
    {
        if(tr[x].l==tr[x].r)return;
        Node &a=tr[x<<1],&b=tr[x<<1|1];
        if (a.lazy==b.lazy&&tr[x].lazy==-1)tr[x].lazy=a.lazy;
    }
    void segmentTree::push_down(ll x)
    {
        if (tr[x].lazy==-1)return;
        tr[x<<1].lazy=tr[x].lazy;
        tr[x<<1|1].lazy=tr[x].lazy;
        tr[x].lazy=-1;
    }
    void segmentTree::bt(ll x,ll l,ll r)
    {
        tr[x]=Node{l,r,0};
        if (l==r)return;
        ll mid=(l+r)>>1;
        bt(x<<1,l,mid);
        bt(x<<1|1,mid+1,r);
    }
    void segmentTree::add(ll x,ll l,ll r,ll tt)
    {
        if (l<=tr[x].l&&tr[x].r<=r&&tr[x].lazy!=-1)
        {
            tr[x].lazy+=tt;
            tr[x].lazy%=mo;
            return;
        }
        ll mid=(tr[x].l+tr[x].r)>>1;
        push_down(x);
        if (l<=mid)add(x<<1,l,r,tt);
        if (mid<r)add(x<<1|1,l,r,tt);
        push_up(x);
    }
    void segmentTree::multiply(ll x,ll l,ll r,ll tt)
    {
        if (l<=tr[x].l&&tr[x].r<=r&&tr[x].lazy!=-1)
        {
            tr[x].lazy*=tt;
            tr[x].lazy%=mo;
            return;
        }
        ll mid=(tr[x].l+tr[x].r)>>1;
        push_down(x);
        if (l<=mid)multiply(x<<1,l,r,tt);
        if (mid<r)multiply(x<<1|1,l,r,tt);
        push_up(x);
    }
    void segmentTree::cover(ll x,ll l,ll r,ll tt)
    {
        if (l<=tr[x].l&&tr[x].r<=r&&tr[x].lazy!=-1)
        {
            tr[x].lazy=tt%mo;
            return;
        }
        ll mid=(tr[x].l+tr[x].r)>>1;
        push_down(x);
        if (l<=mid)cover(x<<1,l,r,tt);
        if (mid<r)cover(x<<1|1,l,r,tt);
        push_up(x);
    }
    ll segmentTree::query(ll x,ll l,ll r,ll tt)
    {
        if (l<=tr[x].l&&tr[x].r<=r&&tr[x].lazy!=-1)
        {
            ll ans=1;
            for(ll i=1;i<=tt;i++)ans*=tr[x].lazy;
            ans*=(tr[x].r-tr[x].l+1);
            return ans%mo;
        }
        ll mid=(tr[x].l+tr[x].r)>>1,ans=0;
        push_down(x);
        if(l<=mid)ans+=query(x<<1,l,r,tt);
        if(mid<r)ans+=query(x<<1|1,l,r,tt);
        push_up(x);
        return ans%mo;
    }
    void work()
    {
        read(n); read(m);
        if (n+m==0)exit(0);
        seg.bt(1,1,n);
        for(ll i=1;i<=m;i++)
        {
            ll id,x,y,tt;
            read(id); read(x); read(y); read(tt);
            if (id==1)seg.add(1,x,y,tt);
            if (id==2)seg.multiply(1,x,y,tt);
            if (id==3)seg.cover(1,x,y,tt);
            if (id==4)printf("%lld
    ",seg.query(1,x,y,tt));
        }
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("aa.in","r",stdin);
    #endif
        while(1)work();
    }
    
    
  • 相关阅读:
    ajax收藏
    excel提取文本格式时分秒中数字的方法并计算成秒的公式
    vi编辑模式中按方向键变ABCD的解决方法
    IIS配置Url重写实现http自动跳转https的重定向方法
    IIS中启用目录浏览功能后不能下载未知扩展名文件的解决方法
    Nginx禁止IP访问,只允许域名访问
    nginx在Window平台http自动跳转https设置方法
    通过清理注册表方式清理window远程连接的历史记录
    DOS批处理添加IP域名,备份与恢复
    windows修改snmp端口号方法
  • 原文地址:https://www.cnblogs.com/mmmqqdd/p/11241062.html
Copyright © 2011-2022 走看看