bzoj2962: 序列操作


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
题解: 线段树。懒得打题解,放张图吧。
代码无脑longlong
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define mod 19940417
#define ll long long
const ll N=60100;
ll n,q;
struct node{
    ll sum[26];
}sa[N*4];
ll c[N][36],aa[N];
ll p1[N*4],d1[N*4];//标记相反数,加数 
node update(node a,node b)
{
    node c;
    for(ll i=1;i<=20;i++) c.sum[i]=0;c.sum[0]=1;
    for(ll i=1;i<=20;i++)
    for(ll j=0;j<=i;j++)
    (c.sum[i]+=(a.sum[j]*b.sum[i-j])%mod+mod)%=mod;
    return c;
}
void built(ll k,ll l,ll r)
{
    sa[k].sum[0]=1;
    if(l==r){sa[k].sum[1]=aa[l];return;}
    ll mid=(l+r)>>1;
    built(k<<1,l,mid);built(k<<1|1,mid+1,r);
    sa[k]=update(sa[k<<1],sa[k<<1|1]);
}
void get_mark(ll k,ll l,ll r,ll v,ll p)
{
    ll f[30];ll len=r-l+1;
    if(p)
    {
        for(ll i=1;i<=20;i++) if(i%2==1) sa[k].sum[i]=(mod-sa[k].sum[i])%mod;
        p1[k]=!p1[k];d1[k]=(mod-d1[k])%mod;
    }
    if(v)
    {
        f[0]=1;for(ll i=1;i<=20;i++) f[i]=(f[i-1]*v+mod)%mod;
        ll temp; 
        for(ll i=20;i>=1;i--)
        {
            temp=0;
            for(ll j=0;j<=i;j++)
            {
            (temp+=((f[j]*sa[k].sum[i-j])%mod*c[len-i+j][j])%mod+mod)%=mod; 
            }
            sa[k].sum[i]=temp;
        }
    }
    d1[k]=(d1[k]+v+mod)%mod;
}
void pushdown(ll k,ll l,ll r)
{
    ll mid=(l+r)>>1;
    get_mark(k<<1,l,mid,d1[k],p1[k]);
    get_mark(k<<1|1,mid+1,r,d1[k],p1[k]);
    d1[k]=0;if (p1[k]) p1[k]=!p1[k];  
}
void insert(ll k,ll l,ll r,ll l1,ll rr,long long v,ll pp){  
  ll mid=(l+r)>>1;  
  if (l1<=l&&r<=rr){get_mark(k,l,r,v,pp);return;}  
  if (p1[k]||d1[k]) pushdown(k,l,r);  
  if (l1<=mid) insert(k<<1,l,mid,l1,rr,v,pp);  
  if (rr>mid) insert(k<<1|1,mid+1,r,l1,rr,v,pp);  
  sa[k]=update(sa[k<<1],sa[k<<1|1]);   
}  
node query(ll k,ll l,ll r,ll l1,ll rr){  
  node ans,t1,t2;ll mid=(l+r)>>1;bool f1(0),f2(0);  
  if (l1<=l&&r<=rr) return sa[k];  
  if (p1[k]||d1[k]) pushdown(k,l,r);   
  if (l1<=mid) t1=query(k<<1,l,mid,l1,rr),f1=1;  
  if (rr>mid) t2=query(k<<1|1,mid+1,r,l1,rr),f2=1;  
  if (!f1) return t2;if (!f2) return t1;ans=update(t1,t2);return ans;  
} 
int main()
{
    scanf("%lld%lld",&n,&q);
    for(ll i=1;i<=n*4;i++) sa[i].sum[0]=1;c[0][0]=1;
    for(ll i=1;i<=n;i++)
    {
        c[i][0]=1;c[i][i]=1;
        for(ll j=1;j<=20;j++)
        c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    }
    for(ll i=1;i<=n;i++)
    scanf("%lld",&aa[i]);built(1,1,n);
    char s[6];
    ll a,b,c;
    for(ll i=1;i<=q;i++)
    {
        scanf("%s",s);
        if(s[0]=='I'){scanf("%lld%lld%lld",&a,&b,&c);insert(1,1,n,a,b,c,0);}
        if(s[0]=='R'){scanf("%lld%lld",&a,&b);insert(1,1,n,a,b,0,1);}
        if(s[0]=='Q'){scanf("%lld%lld%lld",&a,&b,&c);node yu;yu=query(1,1,n,a,b);printf("%lld\n",(yu.sum[c]+mod)%mod);}
    }  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值