bzoj 2962 序列操作 —— 线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962
维护 sum[i] 表示选 i 个的乘积和,合并两个子树就枚举两边选多少,乘起来即可;
取反只需要把奇数个数的乘积和变成相反数即可;
关键是区间 + k:比如对于一个元素,原来是 a, b, c,+ k 变成 (a+k), (b+k), (c+k)
从每个括号里选 a,b,c 或者 k,如果选 j 个 k ,那么就是 sum[i] += sum[i-j] * k^j * C(len-(i-j), j),组合数表示从剩余的位置中选 j 个 k;
详细可以看这个博客:https://blog.csdn.net/qq_35866453/article/details/77998472
注意一下处理 rev 标记和 lzy 标记,顺序是先 reverse 再 add,更改 rev 标记时要把 lzy 标记取反;
调了一上午:
1.各种计算 sum 时,上限原来写的是20,又觉得不好,改成 len,然而应该是 min(len,20) ...
2.query 写得不好的话会 TLE ... 还是模仿了 Narh 的写法,感觉很优秀。
代码如下:
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #define mid ((l+r)>>1)
- using namespace std;
- typedef long long ll;
- int const xn=5e4+,mod=;
- int n,q,cnt=,a[xn],lzy[xn<<],ans[xn];
- ll c[xn][];
- bool rev[xn<<];
- char ch;
- struct N{int ls,rs,len; ll sum[];}t[xn<<];
- int rd()
- {
- int ret=,f=; char ch=getchar();
- while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
- while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
- return f?ret:-ret;
- }
- void init()
- {
- for(int i=;i<=n;i++)c[i][]=;
- for(int i=;i<=n;i++)
- for(int j=;j<=min(i,);j++)
- c[i][j]=(c[i-][j]+c[i-][j-])%mod;
- }
- ll pls(ll a,ll b){a=a+b; while(a>=mod)a-=mod; while(a<)a+=mod; return a;}
- void pushup(int x)
- {
- int ls=t[x].ls,rs=t[x].rs,lm=min(t[x].len,);
- for(int i=;i<=lm;i++)//min!!
- {
- t[x].sum[i]=;
- for(int j=;j<=i;j++)
- t[x].sum[i]=pls(t[x].sum[i],(t[ls].sum[j]*t[rs].sum[i-j])%mod);
- }
- }
- void ad(int x,int k)
- {
- int len=t[x].len,lm=min(len,);
- for(int i=lm;i>=;i--)//min
- for(int j=,pw=k;j<=i;j++,pw=((ll)pw*k)%mod)//
- t[x].sum[i]=pls(t[x].sum[i],t[x].sum[i-j]*pw%mod*c[len-i+j][j]%mod);
- lzy[x]=pls(lzy[x],k);
- }
- void re(int x)
- {
- int lm=min(t[x].len,);
- for(int i=;i<=lm;i+=)t[x].sum[i]=pls(mod,-t[x].sum[i]);//min
- rev[x]^=;
- lzy[x]=pls(mod,-lzy[x]);
- }
- void pushdown(int x)
- {
- int ls=t[x].ls,rs=t[x].rs;
- if(rev[x])re(ls),re(rs),rev[x]=;
- if(lzy[x])ad(ls,lzy[x]),ad(rs,lzy[x]),lzy[x]=;
- }
- void build(int x,int l,int r)
- {
- t[x].sum[]=; t[x].len=r-l+;
- if(l==r){t[x].sum[]=a[l]; return;}
- t[x].ls=++cnt; t[x].rs=++cnt;
- int ls=t[x].ls,rs=t[x].rs;
- build(ls,l,mid); build(rs,mid+,r);
- pushup(x);
- }
- void add(int x,int l,int r,int L,int R,int k)
- {
- if(l>=L&&r<=R){ad(x,k); return;}
- pushdown(x);
- int ls=t[x].ls,rs=t[x].rs;
- if(mid>=L)add(ls,l,mid,L,R,k);
- if(mid<R)add(rs,mid+,r,L,R,k);
- pushup(x);
- }
- void reverse(int x,int l,int r,int L,int R)
- {
- if(l>=L&&r<=R){re(x); return;}
- pushdown(x);
- int ls=t[x].ls,rs=t[x].rs;
- if(mid>=L)reverse(ls,l,mid,L,R);
- if(mid<R)reverse(rs,mid+,r,L,R);
- pushup(x);
- }
- /*
- ll query(int x,int l,int r,int L,int R,int k)
- {
- int ls=t[x].ls,rs=t[x].rs;
- if(l>=L&&r<=R)return t[x].sum[k];
- pushdown(x);
- if(mid>=R)return query(ls,l,mid,L,R,k);
- else if(mid<L)return query(rs,mid+1,r,L,R,k);
- else
- {
- ll ret=0;
- for(int i=0;i<=k;i++)
- ret=pls(ret,query(ls,l,mid,L,R,i)*query(rs,mid+1,r,L,R,k-i)%mod);
- return ret;
- }
- }
- */
- void query(int cr,int l,int r,int L,int R,int k)
- {
- if(l>=L&&r<=R)
- {
- int lm=min(k,r-l+);
- for(int i=k;i>=;i--)
- for(int j=;j<=lm&&j<=i;j++)//j<=i
- ans[i]=((ll)ans[i]+t[cr].sum[j]*ans[i-j])%mod;
- return;
- }
- pushdown(cr);
- if(L<=mid) query(t[cr].ls,l,mid,L,R,k);
- if(mid<R) query(t[cr].rs,mid+,r,L,R,k);
- }
- int main()
- {
- n=rd(); q=rd();
- init();
- for(int i=;i<=n;i++)a[i]=rd();
- build(,,n);
- ans[]=;
- for(int i=,a,b,c;i<=q;i++)
- {
- cin>>ch;
- a=rd(); b=rd();
- if(ch!='R')c=rd();
- if(ch=='I')c=pls(c,),add(,,n,a,b,c);
- if(ch=='R')reverse(,,n,a,b);
- if(ch=='Q')
- // printf("%lld\n",query(1,1,n,a,b,c)%mod);
- {
- for(int i=;i<=c;i++)ans[i]=;
- query(,,n,a,b,c);
- printf("%d\n",ans[c]);
- }
- }
- return ;
- }
bzoj 2962 序列操作 —— 线段树的更多相关文章
- bzoj 2962 序列操作——线段树(卷积?)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962 如果 _,_,_,…… 变成了 (_+k),(_+k),(_+k),…… ,计算就是在 ...
- [bzoj]2962序列操作
[bzoj]2962序列操作 标签: 线段树 题目链接 题意 给你一串序列,要你维护三个操作: 1.区间加法 2.区间取相反数 3.区间内任意选k个数相乘的积 题解 第三个操作看起来一脸懵逼啊. 其实 ...
- 【题解】P4247 [清华集训]序列操作(线段树修改DP)
[题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...
- 【BZOJ-2962】序列操作 线段树 + 区间卷积
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 678 Solved: 246[Submit][Status][Discuss] ...
- bzoj 2962 序列操作
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MB[Submit][Status][Discuss] Description 有一个长度为n的序列, ...
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...
- 【BZOJ-1858】序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1961 Solved: 991[Submit][Status ...
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...
- 【BZOJ2962】序列操作 线段树
[BZOJ2962]序列操作 Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反 ...
随机推荐
- 【Floyd最短路】第七届福建省赛 FZU Problem 2271 X
http://acm.fzu.edu.cn/problem.php?pid=2271 [题意] 给定一个n个点和m条边的无向连通图,问最多可以删去多少条边,使得每两个点之间的距离(最短路长度)不变. ...
- ES6__字符串、数组、对象的扩展
/** * 字符串的扩展 */ // 模板字符串 tab上面的反向符号 // 添加${} // let flag = true; // // let html = `<ul> // < ...
- hiho一下 第四十五周 博弈游戏·Nim游戏·二 [ 博弈 ]
传送门 题目1 : 博弈游戏·Nim游戏·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Alice和Bob这一次准备玩一个关于硬币的游戏:N枚硬币排成一列,有的正面 ...
- 关于Linux内核学习的一点点总结
关于Linux内核学习的一点点总结 关键词:Linux, 操作系统,内核 博客列表 由反汇编C程序来理解计算机是如何工作的 通过分析一个简化版时间片轮转多道程序内核代码来认识操作系统中的进程调度 通过 ...
- ACM常用模板整理
线段树单点修改区间查询 #include<stdio.h> #include<string.h> #include<algorithm> using namespa ...
- chrome插件vimium的安装和使用
vimium工具的作用:使你脱离鼠标,使用键盘方便操作页面,默认对所有网站生效 1.chrome商店里有的,但是,我怎么安装,都不行 2.源码安装:http://vimium.github.io/ h ...
- [Angular] Architectures for Huge Angular Based Enterprise
Using Angular CLI v6, we are able to create library or small application inside a Angular CLI genera ...
- HTML的DIV如何实现垂直居中
外部的DIV必须有如下代码 display:table-cell; vertical-align:middle; 这样可以保证里面的东西,无论是DIV还是文本都可以垂直居中
- iOS开发--URL中汉字出现乱码
NSURL *nurl=[[NSURL alloc] initWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF ...
- Bootstrap的js插件之弹出框(popover)
data-toggle="popover"--使弹出框可以切换状态: title--设置弹出框的标题: data-content--设置弹出框的内容部分: data-placeme ...