bzoj2962 序列操作

2962: 序列操作

Time Limit: 50 Sec  Memory Limit: 256 MB
Submit: 1145  Solved: 378
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

40
19940397
样例说明
  做完第一个操作序列变为1 3 4 4 5。
  第一次询问结果为3*4+3*4+4*4=40。
  做完R操作变成-1 -3 -4 -4 -5。
  做完I操作变为-2 -4 -5 -4 -5。
  第二次询问结果为-2-4-5-4-5=-20。

HINT

  100%的数据n<=50000,q<=50000,初始序列的元素的绝对值<=109,I a b c中保证[a,b]是一个合法区间,|c|<=109,R a b保证[a,b]是个合法的区间。Q a b c中保证[a,b]是个合法的区间1<=c<=min(b-a+1,20)。

Source

分析:线段树套路题.类似:传送门,这类题有一个特征就是需要维护的东西比较少:c <= 20,那么就可以开一个数组分别维护这些东西.
          f[i]表示当前区间选i个数相乘的和,显然一开始f[1] = a[pos].合并的时候f[i] = 左子树的f[i] + 右子树的f[i] + 左子树的f[j] * 右子树的f[k],j+k = i. 考虑两个修改操作对答案的影响.取反操作比较简单,注意到当i是奇数时f[i]才会变号.注意,取反以后一定要通过加上模数取模来变成正数.
          第一个操作有点鬼畜.纸上写几个例子,拆项后会再合并,就差不多能发现规律:,感性理解一下就是c的k次方,c要占k个位置,而另外的位置已经被f选的数给占了,只能在剩下的位置中选c,这大概就是组合数的意义.剩下的都可以通过合并同类项得到.
       一些细节需要注意,比如取反后一定要变成正数再来运算,f[0]一定要强制等于1,用类进行运算一定要先初始化,第一个操作对于f的处理要倒序处理,这些在之前附上链接的那道题中都有体现.
     总之,都是套路啦.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
const ll maxn = 50010,mod = 19940417;
ll n,q;
ll a[maxn],c[maxn][21];

struct node
{
    ll add,cover,f[21],L,R;
    void init()
    {
        add = cover = L = R = 0;
        memset(f,0,sizeof(f));
        f[0] = 1;
    }
} e[maxn << 2];

node pushup(node a,node b)
{
    node c;
    c.init();
    c.L = a.L;
    c.R = b.R;
    ll len1 = c.R - c.L + 1;
    ll len2 = a.R - a.L + 1;
    ll len3 = b.R - b.L + 1;
    for (ll i = 0; i <= min(len2,1LL * 20); i++)
        for (ll j = 0; j <= min(len3,1LL * 20); j++)
        {
            if (i + j > 20)
                break;
            c.f[i + j] = (c.f[i + j] + a.f[i] * b.f[j] % mod) % mod;
        }
    c.f[0] = 1; //易错点
    return c;
}

void fan(ll o)
{
    ll len = e[o].R - e[o].L + 1;
    for (ll i = 1; i <= min(len,1LL * 20); i++)
    {
        if (i % 2 == 1)
        {
            e[o].f[i] = -e[o].f[i];
            e[o].f[i] = (e[o].f[i] + mod) % mod;
        }
    }
    e[o].cover ^= 1;
    e[o].add = -e[o].add;
    e[o].add = (e[o].add + mod) % mod; //取反后一定要变成正数
}

void jia(ll o,ll v)
{
    ll len = e[o].R - e[o].L + 1;
    for (ll i = min(len,1LL * 20);i >= 0; i--) //一定要倒着推
    {
        ll k = v;
        for (ll j = i - 1; j >= 0; j--)
        {
            e[o].f[i] = (e[o].f[i] + e[o].f[j] * c[len - j][i - j] % mod * k % mod) % mod;
            k = k * v % mod;
        }
    }
    e[o].add = (e[o].add + v) % mod;
}

void pushdown(ll o)
{
    if (e[o].cover)
    {
        fan(o * 2);
        fan(o * 2 + 1);
        e[o].cover = 0;
    }
    if (e[o].add)
    {
        jia(o * 2,e[o].add);
        jia(o * 2 + 1,e[o].add);
        e[o].add = 0;
    }
}

void build(ll o,ll l,ll r)
{
    e[o].init();
    e[o].L = l,e[o].R = r;
    if (l == r)
    {
        e[o].f[1] = a[l] % mod;
        return;
    }
    ll mid = (l + r) >> 1;
    build(o * 2,l,mid);
    build(o * 2 + 1,mid + 1,r);
    e[o] = pushup(e[o * 2],e[o * 2 + 1]);
}

void update1(ll o,ll l,ll r,ll x,ll y,ll v)
{
    if (x <= l && r <= y)
    {
        jia(o,v);
        return;
    }
    pushdown(o);
    ll mid = (l + r) >> 1;
    if (x <= mid)
        update1(o * 2,l,mid,x,y,v);
    if (y > mid)
        update1(o * 2 + 1,mid + 1,r,x,y,v);
    e[o] = pushup(e[o * 2],e[o * 2 + 1]);
}

void update2(ll o,ll l,ll r,ll x,ll y)
{
    if (x <= l && r <= y)
    {
        fan(o);
        return;
    }
    pushdown(o);
    ll mid = (l + r) >> 1;
    if (x <= mid)
        update2(o * 2,l,mid,x,y);
    if (y > mid)
        update2(o * 2 + 1,mid + 1,r,x,y);
    e[o] = pushup(e[o * 2],e[o * 2 + 1]);
}

node query(ll o,ll l,ll r,ll x,ll y)
{
    if (x <= l && r <= y)
        return e[o];
    pushdown(o);
    ll mid = (l + r) >> 1;
    if (y <= mid)
        return query(o * 2,l,mid,x,y);
    else if (x > mid)
        return query(o * 2 + 1,mid + 1,r,x,y);
    else
        return pushup(query(o * 2,l,mid,x,mid),query(o * 2 + 1,mid + 1,r,mid + 1,y));
}

int main()
{
    scanf("%lld%lld",&n,&q);
    c[0][0] = 1;
    for (ll i = 1; i <= n; i++)
    {
        c[i][0] = 1;
        for (ll j = 1; j <= 20; j++)
            c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    }
    for (ll i = 1; i <= n; i++)
        scanf("%lld",&a[i]);
    build(1,1,n);
    while (q--)
    {
        char ch[2];
        ll a,b,c;
        scanf("%s",ch);
        if (ch[0] == 'I')
        {
            scanf("%lld%lld%lld",&a,&b,&c);
            update1(1,1,n,a,b,c);
        }
        if (ch[0] == 'R')
        {
            scanf("%lld%lld",&a,&b);
            update2(1,1,n,a,b);
        }
        if (ch[0] == 'Q')
        {
            scanf("%lld%lld%lld",&a,&b,&c);
            node temp = query(1,1,n,a,b);
            printf("%lld
",temp.f[c] % mod);
        }
    }

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/8432376.html