• 【bzoj2962】序列操作 线段树


    题目描述

    有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问[a,b]这一段区间中选择c(c<=20)个数相乘的所有方案的和mod 19940417的值。

    输入

    第一行两个数n,q表示序列长度和操作个数。
    第二行n个非负整数,表示序列。
    接下来q行每行输入一个操作I a b c或者 R a b或者Q a b c意义如题目描述。

    输出

    对于每个询问,输出选出c个数相乘的所有方案的和mod19940417的值。

    样例输入

    5 5
    1 2 3 4 5
    I 2 3 1
    Q 2 4 2
    R 1 5
    I 1 3 -1
    Q 1 5 1

    样例输出

    40


    题解

    线段树

    很容易想到对线段树的每一个节点维护v[0...20],表示从这段区间中选出c个数相乘的乘积之和(注意v[0]=1)。

    然后在区间合并时对于每个c,枚举在左边的i个,在右边的就有c-i个,由于乘法具有分配率,因此直接相乘即可。

    区间取相反数的话直接对于奇数个的取相反数,偶数个的不变即可。

    区间加的推导过程十分复杂,这里放结论:$v'[i]=sumlimits_{j=0}^iC_{len-i+j}^j·v[i-j]·a^j$,其中len是区间长度。这个过程可以使用归纳法推出。

    所以直接递推预处理组合数即可实现区间加。

    注意一下双标记的处理:先处理相反数再处理加,取相反数时直接把加标记也取相反数。

    时间复杂度$O(400nlog n)$

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 50010
    #define mod 19940417
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    using namespace std;
    typedef long long ll;
    ll add[N << 2] , c[N][21];
    int rev[N << 2];
    char str[5];
    struct data
    {
        ll v[21] , si;
        data() {memset(v , 0 , sizeof(v)) , v[0] = si = 1;}
        ll &operator[](int a) {return v[a];}
        data operator+(data a)
        {
            data ans;
            int i , j;
            ans.si = si + a.si;
            for(i = 1 ; i <= 20 ; i ++ )
                for(j = 0 ; j <= i ; j ++ )
                    ans[i] = (ans[i] + v[j] * a[i - j]) % mod;
            return ans;
        }
        data operator+(ll a)
        {
            data ans;
            int i , j;
            ll t;
            ans.si = si;
            for(i = 1 ; i <= 20 ; i ++ )
                for(t = 1 , j = 0 ; j <= i ; j ++ , t = t * a % mod)
                    ans[i] = (ans[i] + v[i - j] * t % mod * c[si - i + j][j]) % mod;
            return ans;
        }
        data operator-()
        {
            data ans = *this;
            int i;
            for(i = 1 ; i <= 20 ; i += 2) ans[i] = (mod - ans[i]) % mod;
            return ans;
        }
    }a[N << 2];
    inline void pushup(int x)
    {
        a[x] = a[x << 1] + a[x << 1 | 1];
    }
    inline void pushdown(int x)
    {
        if(rev[x])
        {
            a[x << 1] = -a[x << 1] , a[x << 1 | 1] = -a[x << 1 | 1];
            add[x << 1] = (mod - add[x << 1]) % mod , add[x << 1 | 1] = (mod - add[x << 1 | 1]) % mod;
            rev[x << 1] ^= 1 , rev[x << 1 | 1] ^= 1;
            rev[x] = 0;
        }
        if(add[x])
        {
            a[x << 1] = a[x << 1] + add[x] , a[x << 1 | 1] = a[x << 1 | 1] + add[x];
            add[x << 1] = (add[x << 1] + add[x]) % mod , add[x << 1 | 1] = (add[x << 1 | 1] + add[x]) % mod;
            add[x] = 0;
        }
    }
    void build(int l , int r , int x)
    {
        if(l == r)
        {
            scanf("%lld" , &a[x][1]) , a[x][1] = (a[x][1] % mod + mod) % mod;
            return;
        }
        int mid = (l + r) >> 1;
        build(lson) , build(rson);
        pushup(x);
    }
    void update(int b , int e , ll v , int l , int r , int x)
    {
        if(b <= l && r <= e)
        {
            a[x] = a[x] + v , add[x] = (add[x] + v) % mod;
            return;
        }
        pushdown(x);
        int mid = (l + r) >> 1;
        if(b <= mid) update(b , e , v , lson);
        if(e > mid) update(b , e , v , rson);
        pushup(x);
    }
    void reverse(int b , int e , int l , int r , int x)
    {
        if(b <= l && r <= e)
        {
            a[x] = -a[x] , add[x] = (mod - add[x]) % mod , rev[x] ^= 1;
            return;
        }
        pushdown(x);
        int mid = (l + r) >> 1;
        if(b <= mid) reverse(b , e , lson);
        if(e > mid) reverse(b , e , rson);
        pushup(x);
    }
    data query(int b , int e , int l , int r , int x)
    {
        if(b <= l && r <= e) return a[x];
        pushdown(x);
        int mid = (l + r) >> 1;
        if(e <= mid) return query(b , e , lson);
        else if(b > mid) return query(b , e , rson);
        else return query(b , e , lson) + query(b , e , rson);
    }
    void init(int n)
    {
        int i , j;
        c[0][0] = 1;
        for(i = 1 ; i <= n ; i ++ )
        {
            c[i][0] = 1;
            for(j = 1 ; j <= 20 ; j ++ )
                c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
        }
    }
    int main()
    {
        int n , m , x , y , z;
        scanf("%d%d" , &n , &m);
        init(n) , build(1 , n , 1);
        while(m -- )
        {
            scanf("%s%d%d" , str , &x , &y);
            if(str[0] == 'I') scanf("%d" , &z) , update(x , y , (z % mod + mod) % mod , 1 , n , 1);
            else if(str[0] == 'R') reverse(x , y , 1 , n , 1);
            else scanf("%d" , &z) , printf("%lld
    " , query(x , y , 1 , n , 1)[z]);
        }
        return 0;
    }
    
  • 相关阅读:
    jQuery 基本选择器
    JavaScriptif while for switch流程控制 JS函数 内置对象
    JavaScrip基本语法
    数据库 存储引擎 表的操作 数值类型 时间类型 字符串类型 枚举集合 约束
    数据库基础知识 管理员 用户登录授权的操作
    粘包的产生原理 以及如何解决粘包问题
    socket TCP DPT 网络编程
    2018年年终总结
    Android技术分享
    No accelerator found
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7707895.html
Copyright © 2020-2023  润新知