【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 ...
随机推荐
- 使用Jquery向一个空白网页动态创建一个iframe,及嵌入页面,和向嵌入页面传参
[csharp] view plaincopyprint?using Microsoft.VisualBasic; using System; using System.Collections; us ...
- js/jquery判断浏览器的方法小结
在网站前端开发中,浏览器兼容性是前端开发框架要解决的第一个问题,要解决兼容性问题就得首先准确判断出浏览器的类型及其版本,而判断浏览器的版本一般只能通过分析浏览器的userAgent才能知道.今天我们把 ...
- 利用javascript对提交数据验证
优点:提交前验证.在客户端进行. <html> <head> <script language="javascript"> function c ...
- python网络编程学习《一》
最近,刚实习完,很喜欢实验楼,但是自己的方向仍然不能确定,自己觉得可选择的空间很大,尽管已经是大四的人了,想到别人都在忙着买职业装,买高跟鞋面试,学习化妆什么的,看看自己,反而开始慢慢关注运动,食疗以 ...
- Jenkins进阶系列之——18Jenkins语言本地化
在Jenkins中,英语一大片,看着各种蛋疼.非常高兴的是,Jenkins作为一个主流流行的持续构建工具,提供了一个本地化语言的配置界面. 你可以找到它,在Jenkins每页的左下角.如下图: 点击帮 ...
- 【AS3】Flash与后台数据交换四种方法整理
随着Flash Player 9的普及,AS3编程也越来越多了,所以这次重新整理AS3下几种与后台数据交换方法.1.URLLoader(URLStream)2.FlashRemoting3.XMLSo ...
- 你的C#代码是怎么跑起来的(二)
接上篇:你的C#代码是怎么跑起来的(一) 通过上篇文章知道了EXE文件的结构,现在来看看双击后是怎样运行的: 双击文件后OS Loader加载PE文件并解析,在PE Optional Header里找 ...
- java并发:线程同步机制之ThreadLocal
1.简述ThreadLocal ThreadLocal实例通常作为静态的私有的(private static)字段出现在一个类中,这个类用来关联一个线程.ThreadLocal是一个线程级别的局部变量 ...
- 也议 js闭包和ie内存泄露原理
可以, 但小心使用. 闭包也许是 JS 中最有用的特性了. 有一份比较好的介绍闭包原理的文档. 有一点需要牢记, 闭包保留了一个指向它封闭作用域的指针, 所以, 在给 DOM 元素附加闭包时, 很可能 ...
- javascript面试题(一)
答案和解析在问题下一行,为白色字体 单选题 1.以下哪条语句会产生运行错误:(a) A.var obj = ();//语法错误 B.var obj = [];//创建数组 C.var obj = {} ...