【BZOJ-2962】序列操作 线段树 + 区间卷积
2962: 序列操作
Time Limit: 50 Sec Memory Limit: 256 MB
Submit: 678 Solved: 246
[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
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)。
Source
Solution
线段树维护区间卷积
我们每个区间维护sum[1~20]分别表示选1~20个数的积的和
然后问题在于合并以及修改
合并非常简单$rt.sum[i]=\sum_{j=1}^{i}ls.sum[j]*rs.sum[i-j]$ (手写小的就可以得到)
至于区间取反,直接对区间的所有奇数$sum$取反,偶数$sum$不变。 因为 偶数里的全是偶数项,负号会抵消
区间修改,问题是下放标记时,我们发现假设我们有三个数a,b,c;我们修改时同时+x,那么他们的变化就是
$(a+x)*(b+x)*(c+x)=abc+x(ab+ac+bc)+x^{2}(a+b+c)+x^{3}$这样我们发现,拓展到之后可以得到$sum[i]=\sum_{j=0}^{i}sum[i-j]*C_{sz-j}^{i}*x^{i-j}$
然后我们就可以利用线段树维护了,特别地$sum[0]=1$,中间过程会爆int;
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 80010
#define P 19940417
int N,Q,C[MAXN][];
namespace SegmentTree
{
struct SumNode{int sum[];};
struct SegmentTreeNode{int l,r,size,tag; SumNode p; bool rev;}tree[MAXN<<];
#define ls now<<1
#define rs now<<1|1
inline void Add(int &x,int y) {x+=y; while (x>=P) x-=P; while (x<) x+=P;}
inline SumNode Merge(SegmentTreeNode x,SegmentTreeNode y)
{
SumNode re; re.sum[]=;
for (int i=; i<=; i++)
{
re.sum[i]=(x.p.sum[i]+y.p.sum[i])%P;
for (int j=; j<=i-; j++)
Add(re.sum[i],(LL)x.p.sum[j]*y.p.sum[i-j]%P);
}
return re;
}
inline void Update(int now) {tree[now].p=Merge(tree[ls],tree[rs]);}
inline void rever(int now)
{
tree[now].rev^=;
if (tree[now].tag) tree[now].tag=(P-tree[now].tag%P)%P;
for (int i=; i<=; i++) if ((i&) && tree[now].p.sum[i]) tree[now].p.sum[i]=(P-tree[now].p.sum[i])%P;
}
inline void change(int now,int D)
{
Add(tree[now].tag,D);
for (int t=D,i=; i; i--,t=D)
{
for (int j=i-; j; j--,t=(LL)t*D%P)
Add(tree[now].p.sum[i],(LL)t*tree[now].p.sum[j]%P*C[tree[now].size-j][i-j]%P);
Add(tree[now].p.sum[i],(LL)t*C[tree[now].size][i]%P);
}
}
inline void PushDown(int now)
{
if (tree[now].rev) {rever(ls); rever(rs); tree[now].rev=;}
if (tree[now].tag) {change(ls,tree[now].tag); change(rs,tree[now].tag); tree[now].tag=;}
}
inline void BuildTree(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r; tree[now].size=r-l+;
tree[now].p.sum[]=; tree[now].tag=; tree[now].rev=;
if (l==r) {tree[now].p.sum[]=(read()+P)%P; return;}
int mid=(l+r)>>;
BuildTree(ls,l,mid); BuildTree(rs,mid+,r);
Update(now);
}
inline void Reverse(int now,int L,int R)
{
int l=tree[now].l,r=tree[now].r;
if (L<=l && R>=r) {rever(now); return;}
PushDown(now);
int mid=(l+r)>>;
if (L<=mid) Reverse(ls,L,R);
if (R>mid) Reverse(rs,L,R);
Update(now);
}
inline void Change(int now,int L,int R,int D)
{
int l=tree[now].l,r=tree[now].r;
if (L<=l && R>=r) {change(now,D); return;}
PushDown(now);
int mid=(l+r)>>;
if (L<=mid) Change(ls,L,R,D);
if (R>mid) Change(rs,L,R,D);
Update(now);
}
inline SegmentTreeNode Query(int now,int L,int R,int D)
{
int l=tree[now].l,r=tree[now].r;
if (L==l && R==r) return tree[now];
PushDown(now);
int mid=(l+r)>>; SegmentTreeNode re;
if (R<=mid) return Query(ls,L,R,D);
else if (L>mid) return Query(rs,L,R,D);
else return re.p=Merge(Query(ls,L,mid,D),Query(rs,mid+,R,D)),re;
}
}
void GetC()
{
C[][]=;
for (int i=; i<=N; i++)
{
C[i][]=;
for (int j=; j<=min(i,); j++) C[i][j]=(C[i-][j]+C[i-][j-])%P;
}
}
using namespace SegmentTree;
int main()
{
// freopen("sequence.in","r",stdin);
// freopen("sequence.out","w",stdout);
N=read(),Q=read();
GetC();
SegmentTree::BuildTree(,,N);
// for (int i=1; i<=N; i++) printf("%I64d ",Query(1,1,N,i).p.sum[i]); puts("");
// puts("============================================");
while (Q--)
{
char opt[]; scanf("%s",opt); int x,y,z;
switch (opt[])
{
case 'I' : x=read(),y=read(),z=(read()+P)%P; SegmentTree::Change(,x,y,z); break;
case 'Q' : x=read(),y=read(),z=read(); printf("%d\n",SegmentTree::Query(,x,y,z).p.sum[z]); break;
case 'R' : x=read(),y=read(); SegmentTree::Reverse(,x,y); break;
}
// puts("============================================");
// for (int i=1; i<=N; i++) printf("%d\n",Query(1,1,N,i).p.sum[i]); puts("");
// printf("%d %d %d\n",x,y,z);
// puts("============================================");
}
return ;
}
%来%去太鬼畜了
数组少打一个0,BZOJ楞是WA,就是不报RE,小数据妥妥拍不到,纸张
差点搞得自己以后再也不能叫char哥....
【BZOJ-2962】序列操作 线段树 + 区间卷积的更多相关文章
- bzoj 2962 序列操作——线段树(卷积?)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962 如果 _,_,_,…… 变成了 (_+k),(_+k),(_+k),…… ,计算就是在 ...
- bzoj 2962 序列操作 —— 线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962 维护 sum[i] 表示选 i 个的乘积和,合并两个子树就枚举两边选多少,乘起来即可: ...
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...
- [bzoj]2962序列操作
[bzoj]2962序列操作 标签: 线段树 题目链接 题意 给你一串序列,要你维护三个操作: 1.区间加法 2.区间取相反数 3.区间内任意选k个数相乘的积 题解 第三个操作看起来一脸懵逼啊. 其实 ...
- 【题解】P4247 [清华集训]序列操作(线段树修改DP)
[题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...
- Bzoj 1798: [Ahoi2009]Seq 维护序列seq(线段树区间操作)
1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可 ...
- hdu4521-小明系列问题——小明序列(线段树区间求最值)
题意:求最长上升序列的长度(LIS),但是要求相邻的两个数距离至少为d,数据范围较大,普通dp肯定TLE.线段树搞之就可以了,或者优化后的nlogn的dp. 代码为 线段树解法. #include ...
- bzoj 2962 序列操作
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MB[Submit][Status][Discuss] Description 有一个长度为n的序列, ...
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...
随机推荐
- uploadify firefox 401
uploadify在firefox下上传会报401错误:这是因为java的框架把其拦截了 拦截的原因是,firefox下的flash在请求和发送请求的时候不会携带cookie和session过去,造成 ...
- 127.0.0.1、0.0.0.0和本机IP地址的区别和使用
一.表面上的区别如下: 首先假设本机有多个网卡:eth0 :192.168.0.1 eth1:192.168.1.1 lo: 127.0.0.1 0.0.0.0 不能ping通,代 ...
- 将某个Qt4项目升级到Qt5遇到的问题[转]
该Qt4项目以前是使用Qt4.7.4 MSVC2008开发的,因为使用到了OWC10(Office Web Components),使用MSVC编译器的话无法正常升级到Qt4.8.x和Qt5,于是将编 ...
- Theano2.1.12-基础知识之使用GPU
来自:http://deeplearning.net/software/theano/tutorial/using_gpu.html using the GPU 想要看GPU的介绍性的讨论和对密集并行 ...
- CUDA2.2-原理之存储器访问
本小节来自<大规模并行处理器编程实战>第四节,该书是很好的从内部原理结构上来讲述了CUDA的,对于理解CUDA很有帮助,借以博客的形式去繁取间,肯定会加入自己个人理解,所以有错误之处还望指 ...
- StackExchange.Redis--纯干货喂饱你
Redis和StackExchange.Redis redis有多个数据库1.redis 中的每一个数据库,都由一个 redisDb 的结构存储.其中,redisDb.id 存储着 redis 数据库 ...
- WPF 小技巧
在使用mvvm模式开发时,对于Command的绑定是一件很伤脑筋的事情,尽管有强大的Blend类库支持: xmlns:Custom="http://www.galasoft.ch/mvvml ...
- Pathoto项目:AWS+golang+beego搭建
帮兄弟写了一个网站,由于要在国外使用,选择了AWS作为服务器. 不知道后面的价格如何,12个月免费的确吸引了我. 花费3天时间,从注册到服务器搭建访问,终于搞定了.下面记录一下其中容易出错的命令. 1 ...
- hihocoder 1260
之前做过的oj, acm题目忘了很多了, 又要开始要刷题了, go on! #1260 : String Problem I 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描 ...
- linux安装phpmyadmin
1 配置好MySQL 后启动mysql (service mysqld start); 2 下载phpmyadmin 包,解压只phpmyadmin (解压命令:zip -r abc.zip abc ...