BZOJ_2962_序列操作_线段树
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
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
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)。
每个区间维护F[i]表示当c=i时这个区间的答案。
然后可以暴力合并区间的答案,上传和查询同理。
难点在于两个修改。
取相反数的操作显然只对i为奇数的F[i]取相反数,偶数不变。
区间加x时,假设从${a,b,c}$到${a+x,b+x,c+x}$,那么$(a+x)*(b+x)+(b+x)*(c+x)+(a*x)+(c*x)=ab+ac+bc+2x(a+b+c)+3x^{2}$。
有一些是我们已经知道的信息,剩下的那些x的系数是组合数,预处理出来即可。
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 50050
#define mod 19940417
#define ls p<<1
#define rs p<<1|1
int n,m,C[N][22];
struct node {
int add,rev,s[22],siz;
node() {memset(s,0,sizeof(s));rev=add=siz=0;}
node operator + (const node &x) const {
node re;
int i,j;
for(i=0;i<=20;i++) {
for(j=0;i+j<=20;j++) {
re.s[i+j]=(re.s[i+j]+1ll*s[i]*x.s[j]%mod+mod)%mod;
}
}
re.siz=siz+x.siz;
return re;
}
void rev_() {
int i;
for(i=1;i<=20;i+=2) s[i]=(mod-s[i])%mod;
}
void add_(int d) {
int i,j;
int t;
for(i=min(siz,20);i;i--) {
for(t=d,j=1;j<i;j++,t=1ll*t*d%mod) s[i]=(s[i]+1ll*t*s[i-j]%mod*C[siz-i+j][j]%mod)%mod;
s[i]=(s[i]+1ll*C[siz][i]*t%mod)%mod;
}
}
}t[N<<2];
void pushdown(int p) {
if(t[p].rev) {
t[ls].rev_(); t[rs].rev_();
t[ls].add=(mod-t[ls].add)%mod; t[rs].add=(mod-t[rs].add)%mod;
t[ls].rev^=1; t[rs].rev^=1;
t[p].rev=0;
}
if(t[p].add) {
int d=t[p].add;
t[ls].add_(d); t[rs].add_(d);
t[ls].add=(t[ls].add+d)%mod; t[rs].add=(t[rs].add+d)%mod;
t[p].add=0;
}
}
void build(int l,int r,int p) {
if(l==r) {
int x;
scanf("%d",&x);
x=(x%mod+mod)%mod;
t[p].s[0]=1; t[p].s[1]=x; t[p].siz=1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,ls); build(mid+1,r,rs);
t[p]=t[ls]+t[rs];
}
node query(int l,int r,int x,int y,int p) {
if(x<=l&&y>=r) return t[p];
pushdown(p);
int mid=(l+r)>>1;
if(y<=mid) return query(l,mid,x,y,ls);
if(x>mid) return query(mid+1,r,x,y,rs);
return query(l,mid,x,y,ls)+query(mid+1,r,x,y,rs);
}
void update(int l,int r,int x,int y,int v,int p) {
if(x<=l&&y>=r) {
t[p].add_(v); (t[p].add+=v)%=mod;
return ;
}
pushdown(p);
int mid=(l+r)>>1;
if(x<=mid) update(l,mid,x,y,v,ls);
if(y>mid) update(mid+1,r,x,y,v,rs);
t[p]=t[ls]+t[rs];
}
void reverse(int l,int r,int x,int y,int p) {
if(x<=l&&y>=r) {
t[p].rev_(); t[p].rev^=1; t[p].add=(mod-t[p].add)%mod;
return ;
}
pushdown(p);
int mid=(l+r)>>1;
if(x<=mid) reverse(l,mid,x,y,ls);
if(y>mid) reverse(mid+1,r,x,y,rs);
t[p]=t[ls]+t[rs];
}
char opt[10];
int main() {
int i,x,y,z,j;
scanf("%d%d",&n,&m);
for(i=0;i<=n;i++) C[i][0]=C[i][i]=1;
for(i=1;i<=n;i++) {
int t=min(20,i);
for(j=1;j<=t;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
build(1,n,1);
while(m--) {
scanf("%s%d%d",opt,&x,&y);
if(opt[0]!='R') scanf("%d",&z);
if(opt[0]=='I') {
z=(z%mod+mod)%mod;
update(1,n,x,y,z,1);
}else if(opt[0]=='R') {
reverse(1,n,x,y,1);
}else {
printf("%d\n",(query(1,n,x,y,1).s[z]%mod+mod)%mod);
}
}
}
BZOJ_2962_序列操作_线段树的更多相关文章
- BZOJ_1858_[Scoi2010]序列操作_线段树
BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...
- [bzoj2962]序列操作_线段树_区间卷积
序列操作 bzoj-2962 题目大意:给定一个n个数的正整数序列,m次操作.支持:1.区间加:2.区间取相反数:3.区间求选c个数的乘积和. 注释:$1\le n,m\le 5\cdot 10^4$ ...
- 【BZOJ1858】序列操作(线段树)
[BZOJ1858]序列操作(线段树) 题面 BZOJ 题解 这题思路很简单,细节很烦,很码 维护区间翻转和区间赋值标记 当打到区间赋值标记时直接覆盖掉翻转标记 下放标记的时候先放赋值标记再放翻转标记 ...
- 【BZOJ2962】序列操作(线段树)
[BZOJ2962]序列操作(线段树) 题面 BZOJ 题解 设\(s[i]\)表示区间内选择\(i\)个数的乘积的和 考虑如何向上合并? \(s[k]=\sum_{i=0}^klson.s[i]*r ...
- [SCOI2010]序列操作 BZOJ1858 线段树
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...
- BZOJ1858 [Scoi2010]序列操作(线段树)
题目链接 [Scoi2010]序列操作 考验代码能力的一道好题. 思想还是很简单的(直接上线段树),但是比较难写. #include <bits/stdc++.h> using names ...
- bzoj1858SCOI 序列操作 (线段树)
题目大意: 给定一个长度为n的01序列为,现在有m种操作 \(0\ a\ b\) 把\([a,b]\)的数全部修改为0 \(1\ a\ b\) 把\([a,b]\)的数全部修改为1 \(2\ a\ b ...
- 序列操作 BZOJ2962 线段树
分析: 数据范围表示:c特别的小(c<20) 我们可以考虑nlogn*c^2的算法. 线段树维护区间信息:f[i]表示在[l,r]这段区间中选择i个数相乘的和. 因此,我们可以将区间看成一个点, ...
- 2019.01.04 bzoj2962: 序列操作(线段树+组合数学)
传送门 线段树基础题. 题意:要求维护区间区间中选择ccc个数相乘的所有方案的和(c≤20c\le20c≤20),支持区间加,区间取负. 由于c≤20c\le20c≤20,因此可以对于每个线段树节点可 ...
随机推荐
- [转]web服务器压力测试工具
http_load学习心得: 测试网站每秒所能承受的平均访问量(吞吐量) http_load -parallel 5 -fetches 1000 urls.txt这段命令行是同时使用5个进程,随机访问 ...
- Linux部署集群.NET网站
一.Linux下面安装需要软件 我们这里需要安装的软件有: 1) Mono 3.2.8 : C#跨平台编译器,能使.Net运行与Linux下,目前.net 4.0可以完美运行在该平台下 2) ngin ...
- 与班尼特·胡迪一起找简单规律(HZOJ-2262)
与班尼特·胡迪一起找简单规律 Time Limit: 1 s Memory Limit: 256 MB Description 班尼特·胡迪发现了一个简单规律 给定一个数列,1 , 1 ...
- NewLife.Net——构建可靠的网络服务
网络程序应该注册成为系统服务,以保证其自启动以及稳定可靠运行! 这一场,讲讲怎么建立一个生产级别的网络服务. 老规矩,先上源码:https://github.com/nnhy/NewLife.Net. ...
- SOFA 源码分析— 自定义路由寻址
前言 SOFA-RPC 中对服务地址的选择也抽象为了一条处理链,由每一个 Router 进行处理.同 Filter 一样, SOFA-RPC 对 Router 提供了同样的扩展能力. 那么就看看 SO ...
- Java单例模式(Singleton)以及实现
一. 什么是单例模式 因程序需要,有时我们只需要某个类同时保留一个对象,不希望有更多对象,此时,我们则应考虑单例模式的设计. 二. 单例模式的特点 1. 单例模式只能有一个实例. 2. 单例类必须创建 ...
- python爬虫入门(四)利用多线程爬虫
多线程爬虫 先回顾前面学过的一些知识 1.一个cpu一次只能执行一个任务,多个cpu同时可以执行多个任务2.一个cpu一次只能执行一个进程,其它进程处于非运行状态3.进程里包含的执行单元叫线程,一个进 ...
- 15.linux基础
1.目录 /:根目录,一般根目录下只存放目录,在Linux下有且只有一个根目录.所有的东西都是从这里开始.当你在终端里输入“/home”,你其实是在告诉电脑,先从/(根目录)开始,再进入到home目录 ...
- android获取手机机型、厂商、deviceID基本信息
/** * 系统工具类 */ public class SystemUtil { /** * 获取当前手机系统语言. * * @return 返回当前系统语言.例如:当前设置的是"中文-中国 ...
- django项目部署上线
前言 完善的django项目上线,有很多种上线的方法,比如apache, uwsgi, nginx等.这里只介绍2种,一种是django自带的,另外一种则是nginx + uwsgi完成介绍.这里的系 ...