分析:

数据范围表示:c特别的小(c<20)

我们可以考虑nlogn*c^2的算法。

线段树维护区间信息:f[i]表示在[l,r]这段区间中选择i个数相乘的和。

因此,我们可以将区间看成一个点,在PushUp的时候用背包的方式更新父节点。(仔细观察发现这是卷积)

剩下的就是一些优化了...

附上代码:

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <iostream>
using namespace std;
#define N 50005
#define mod 19940417
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
int C[N][21],a[N],n,Q;
char s[10];
struct node
{
ll f[21],tag,add;
int siz;
node ()
{
memset(f,0,sizeof(f));
siz=tag=add=0;
}
node operator +(const node &b)
{
node c;
c.f[0]=1;
for(int i=1;i<=20;i++)
{
for(int j=0;j<=i;j++)
{
c.f[i]+=f[j]*b.f[i-j]%mod;
c.f[i]%=mod;
}
}
c.siz=siz+b.siz;
return c;
}
void plus(ll x)
{
add+=x;
add%=mod;
for(int i=min(siz,20);i;i--)
{
ll y=x;
for(int j=1;j<=i;j++)
{
f[i]=(f[i]+y*f[i-j]%mod*C[siz-i+j][j]%mod)%mod;
y=y*x%mod;
}
}
}
void rev()
{
tag^=1;
add=(mod-add)%mod;
for(int i=min(siz,20);i;i--)
{
if(i&1)f[i]=(mod-f[i])%mod;
}
}
}tr[N<<2];
void PushUp(int rt)
{
tr[rt]=tr[rt<<1]+tr[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r)
{
tr[rt].f[1]=a[l];
tr[rt].f[0]=tr[rt].siz=1;
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
PushUp(rt);
}
void PushDown(int rt)
{
if(tr[rt].tag)
{
tr[rt<<1].rev();
tr[rt<<1|1].rev();
tr[rt].tag=0;
}
if(tr[rt].add)
{
tr[rt<<1].plus(tr[rt].add);
tr[rt<<1|1].plus(tr[rt].add);
tr[rt].add=0;
}
}
void Update(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
tr[rt].plus(c);
return ;
}
PushDown(rt);
int m=(l+r)>>1;
if(m>=L)Update(L,R,c,lson);
if(m<R)Update(L,R,c,rson);
PushUp(rt);
}
void Update_rev(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
tr[rt].rev();
return ;
}
PushDown(rt);
int m=(l+r)>>1;
if(m>=L)Update_rev(L,R,lson);
if(m<R)Update_rev(L,R,rson);
PushUp(rt);
}
node query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return tr[rt];
}
PushDown(rt);
int m=(l+r)>>1;
if(m>=R)return query(L,R,lson);
if(m<L)return query(L,R,rson);
return query(L,R,lson)+query(L,R,rson);
}
int main()
{
scanf("%d%d",&n,&Q);
C[0][0]=1;
for(int i=1;i<=n;i++)
{
C[i][0]=1;
for(int j=1;j<=20;j++)
{
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
build(1,n,1);
while(Q--)
{
int x,y,z;
scanf("%s%d%d",s,&x,&y);
if(s[0]=='I')
{
scanf("%d",&z);
Update(x,y,z,1,n,1);
}else if(s[0]=='R')
{
Update_rev(x,y,1,n,1);
}else
{
scanf("%d",&z);
printf("%lld\n",(query(x,y,1,n,1).f[z]+mod)%mod);
}
}
return 0;
}

  

序列操作 BZOJ2962 线段树的更多相关文章

  1. 【BZOJ2962】序列操作(线段树)

    [BZOJ2962]序列操作(线段树) 题面 BZOJ 题解 设\(s[i]\)表示区间内选择\(i\)个数的乘积的和 考虑如何向上合并? \(s[k]=\sum_{i=0}^klson.s[i]*r ...

  2. BZOJ_1858_[Scoi2010]序列操作_线段树

    BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...

  3. 【BZOJ1858】序列操作(线段树)

    [BZOJ1858]序列操作(线段树) 题面 BZOJ 题解 这题思路很简单,细节很烦,很码 维护区间翻转和区间赋值标记 当打到区间赋值标记时直接覆盖掉翻转标记 下放标记的时候先放赋值标记再放翻转标记 ...

  4. [bzoj2962]序列操作_线段树_区间卷积

    序列操作 bzoj-2962 题目大意:给定一个n个数的正整数序列,m次操作.支持:1.区间加:2.区间取相反数:3.区间求选c个数的乘积和. 注释:$1\le n,m\le 5\cdot 10^4$ ...

  5. 2019.01.04 bzoj2962: 序列操作(线段树+组合数学)

    传送门 线段树基础题. 题意:要求维护区间区间中选择ccc个数相乘的所有方案的和(c≤20c\le20c≤20),支持区间加,区间取负. 由于c≤20c\le20c≤20,因此可以对于每个线段树节点可 ...

  6. [SCOI2010]序列操作 BZOJ1858 线段树

    题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...

  7. BZOJ1858 [Scoi2010]序列操作(线段树)

    题目链接 [Scoi2010]序列操作 考验代码能力的一道好题. 思想还是很简单的(直接上线段树),但是比较难写. #include <bits/stdc++.h> using names ...

  8. bzoj1858SCOI 序列操作 (线段树)

    题目大意: 给定一个长度为n的01序列为,现在有m种操作 \(0\ a\ b\) 把\([a,b]\)的数全部修改为0 \(1\ a\ b\) 把\([a,b]\)的数全部修改为1 \(2\ a\ b ...

  9. BZOJ_2962_序列操作_线段树

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

随机推荐

  1. ubuntu 13.10 install wireshark

    ubuntu 13.10 install wireshark 今天在使用java jsoup操作remote server的是否,在本地执行可以成功返回内容,然后打成jar包,使用shell在 ser ...

  2. win10右键添加在此处打开powershell

    如图: 你想要的效果可能就是这个吧?但是找了好久没有找到方法?爸比告诉你,不需要修改任何东西, 解锁新姿势: 在文件夹空白处,按住shift同时鼠标右击,发现没??发现没!!!!

  3. java-随机生成用户名(中文版及英文版)

    开发中遇到用户名随机生成的问题,总结了两个(中文版和英文版),相关方法在此,方便直接调用. 如下: //自动生成名字(中文) public static String getRandomJianHan ...

  4. 在win10下给vs2013配置opencv3.0

    opencv这玩意是真难搞呀. 先吐槽下..... 下面进入正文. 1准备工具: opencv3.0+vs2013 这里面不提供链接下载,自行谷歌百度. 2配置环境: a.打开下载好的opencv(解 ...

  5. 循环中else的用法

    name = 'hello' for x in name: print(x) if x == 'l': break #退出for循环 else: print("==for循环过程中,如果没有 ...

  6. NoHttp封装--03 缓存

    1.Default模式,也是没有设置缓存模式时的默认模式 这个模式实现http协议中的内容,比如响应码是304时,当然还会结合E-Tag和LastModify等头. StringRequest req ...

  7. 最近面了不少java开发,据此来说下我的感受:哪怕事先只准备1小时,成功概率也能大大提升

    本人最近几年一直在做java后端方面的技术面试官,而在最近两周,又密集了面试了一些java初级和高级开发的候选人,在面试过程中,我自认为比较慎重,遇到问题回答不好的候选人,我总会再三从不同方面提问,只 ...

  8. Python_struct模块操作二进制文件

    ''' 使用struct模块写入二进制文件 ''' import struct n=130000000 x=96.45 b=True s='a1@中国' sn=struct.pack('if?',n, ...

  9. dmraid 用法

    dmraid 全名为设备对应器磁盘阵列(Device Mapper RAID),利用Linux内核提供的设备对应器(Device Mapper)机制 ,为多种磁盘阵列设备提供磁盘阵列的设备文件,让用户 ...

  10. Netty中如何写大型数据

    因为网络饱和的可能性,如何在异步框架中高效地写大块的数据是一个特殊的问题.由于写操作是非阻塞的,所以即使没有写出所有的数据,写操作也会在完成时返回并通知ChannelFuture.当这种情况发生时,如 ...