codeforces316E3 Summer Homework(线段树,斐波那契数列)
题目大意
给定一个n个数的数列,m个操作,有三种操作:
\(1\ x\ v\) 将\(a_x\)的值修改成v
$2\ l\ r\ $ 求 \(\sum_{i=l}^r x_i*f_{i-l}\) 其中对于\(f\)数组 \(f_0=1\ ,f_1=1\ ,f_i=f_{i-1}+f_{i-2}\) (就是斐波那契数列)
$3\ l\ r\ x\ $ 让\(a_i+x,i\in[l,r]\)
其中$n\le 100000,m\le 100000$
一看这个题QwQ,就知道是线段树题
QwQ那么怎么维护节点信息和合并区间呢
来举个栗子试一下
对于系数分别为\(1\ 1,1\ 2\)来说
将二者相加变为\(2\ 3\)也就是以第三个元素开头的系数序列了~
由于fib序列相加还是fib序列
哇,那这么说,这个题目所给的求和的操作,也是可以通过已知矩阵乘转移矩阵快速得到目标矩阵
那么!就可以通过这个东西来转移了!
0 & 1 \\
1& 1 \\
\end{bmatrix}
\]
所以!对于左右区间来说,合并的时候,只需要把右区间乘上左区间的长度次方(就相当于把右边这个区间的变为$f_{mid-l+1}$项开头)
同时,我们发现要进行矩阵转移,必须记录当前这个区间的元素从\(f_0\)开始和\(f_1\)开始的两个值,才能够进行矩阵计算
QwQ因为我不会矩阵乘法呀!
所以我是选择手动展开了矩阵的n次方
最后假设是求矩阵的n次方的话
那么最终的矩阵应为
{fib}_{n-2} & {fib}_{n-1} \\
{fib}_{n-1}& {fib}_{n} \\
\end{bmatrix}
\]
~只需要预处理一下fib序列和fib序列的前缀和就行了
void up(int root)
{
ll len = f[2*root].len;
f[root].len=(f[2*root].len+f[2*root+1].len)%mod;
f[root].fir=(f[2*root].fir+f[2*root+1].fir*get(len-2)+f[2*root+1].sec*fib[len-1])%mod;
f[root].sec=(f[2*root].sec+f[2*root+1].fir*fib[len-1]+f[2*root+1].sec*fib[len])%mod;
}
接着,我们考虑,对3操作
如果让一个区间加x,就是让这个区间加x*fib前缀和的区间长度-1项(因为\(f_0=1\))(求答案的是从\(f_0\)开始乘)
emmmm所以也是可以直接做了咯(记得从1开始乘的那个信息需要-add[root])
void pushdown(int root,int l,int r)
{
if (add[root])
{
add[2*root]=(add[2*root]+add[root])%mod;
add[2*root+1]=(add[2*root+1]+add[root])%mod;
f[2*root].fir=(f[2*root].fir+add[root]*sum[f[2*root].len-1])%mod;
f[2*root].sec=(f[2*root].sec+add[root]*sum[f[2*root].len]-add[root])%mod;
f[2*root+1].fir=(f[2*root+1].fir+add[root]*sum[f[2*root+1].len-1])%mod;
f[2*root+1].sec=(f[2*root+1].sec+add[root]*sum[f[2*root+1].len]-add[root])%mod; //之所以-1是因为要减掉fib[0]
add[root]=0;
}
}
update和change和build都差不多~
需要注意的是!!!!!!!!!
query的时候,不能直接\(return\ f[root].fir\)
因为如果让区间为\([l,r]\),就需要将这一段嫁接到\([x,l-1]\)的后面,对,所以也需要想之前合并的时候那样乘一个fib
if (x<=l && r<=y)
{
int len = l-1-x+1;
if (len==0) return f[root].fir;
return f[root].fir*get(len-2)+f[root].sec*get(len-1);
}
其他的都差不多了啦
直接上代码!
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#define ll long long
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2e5+1e2;
const int mod = 1000000000;
struct Node
{
ll fir,sec,len;
};
Node f[4*maxn];
ll add[4*maxn];
ll a[maxn];
ll fib[maxn],sum[maxn];
int n,m;
void init()
{
fib[0]=1,fib[1]=1;
for (int i=2;i<=n;i++) fib[i]=(fib[i-1]+fib[i-2])%mod;
sum[0]=1;
for (int i=1;i<=n;i++) sum[i]=(sum[i-1]+fib[i])%mod;
}
ll get(int x)
{
if (x<0) return 0;
else return fib[x];
}
void up(int root)
{
ll len = f[2*root].len;
f[root].len=(f[2*root].len+f[2*root+1].len)%mod;
f[root].fir=(f[2*root].fir+f[2*root+1].fir*get(len-2)+f[2*root+1].sec*fib[len-1])%mod;
f[root].sec=(f[2*root].sec+f[2*root+1].fir*fib[len-1]+f[2*root+1].sec*fib[len])%mod;
}
void pushdown(int root,int l,int r)
{
if (add[root])
{
add[2*root]=(add[2*root]+add[root])%mod;
add[2*root+1]=(add[2*root+1]+add[root])%mod;
f[2*root].fir=(f[2*root].fir+add[root]*sum[f[2*root].len-1])%mod;
f[2*root].sec=(f[2*root].sec+add[root]*sum[f[2*root].len]-add[root])%mod;
f[2*root+1].fir=(f[2*root+1].fir+add[root]*sum[f[2*root+1].len-1])%mod;
f[2*root+1].sec=(f[2*root+1].sec+add[root]*sum[f[2*root+1].len]-add[root])%mod; //之所以-1是因为要减掉fib[0]
add[root]=0;
}
}
void build(int root,int l,int r)
{
if (l==r)
{
f[root].sec=f[root].fir=a[l]%mod;
f[root].len=1;
return;
}
int mid = (l+r) >> 1;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
up(root);
}
void update(int root,int l,int r,int x,int y,int p)
{
if (x<=l && r<=y)
{
add[root]=(add[root]+p)%mod;
f[root].fir=(f[root].fir+sum[r-l]*p)%mod;
f[root].sec=(f[root].sec+sum[r-l+1]*p-p)%mod;
return;
}
pushdown(root,l,r);
int mid = (l+r) >> 1;
if (x<=mid) update(2*root,l,mid,x,y,p);
if (y>mid) update(2*root+1,mid+1,r,x,y,p);
up(root);
}
void change(int root,int l,int r,int x,int p)
{
if (l==r)
{
f[root].fir=f[root].sec=p%mod;
add[root]=0;
f[root].len=1;
return;
}
pushdown(root,l,r);
int mid = (l+r) >> 1;
if (x<=mid) change(2*root,l,mid,x,p);
if (x>mid) change(2*root+1,mid+1,r,x,p);
up(root);
}
ll query(int root,int l,int r,int x,int y)
{
if (x<=l && r<=y)
{
int len = l-1-x+1;
if (len==0) return f[root].fir;
return f[root].fir*get(len-2)+f[root].sec*get(len-1);
}
int mid = (l+r) >> 1;
pushdown(root,l,r);
ll ans=0;
if (x<=mid) ans=(ans+query(2*root,l,mid,x,y))%mod;
if (y>mid) ans=(ans+query(2*root+1,mid+1,r,x,y))%mod;
return ans%mod;
}
int main()
{
scanf("%d%d",&n,&m);
init();
for (int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
//cout<<query(1,1,n,1,4)<<endl;
for (int i=1;i<=m;i++)
{
int opt;
opt=read();
if (opt==1)
{
int x=read();
ll y=read();
change(1,1,n,x,y);
}
if (opt==2)
{
int x=read(),y=read();
//cout<<x<<" "<<y<<endl;
printf("%lld\n",query(1,1,n,x,y));
//cout<<query(1,1,n,1,4)<<endl;
}
if (opt==3)
{
int x=read(),y=read();
ll z=read();
update(1,1,n,x,y,z);
}
}
return 0;
}
codeforces316E3 Summer Homework(线段树,斐波那契数列)的更多相关文章
- [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)
[Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...
- Codeforces 446-C DZY Loves Fibonacci Numbers 同余 线段树 斐波那契数列
C. DZY Loves Fibonacci Numbers time limit per test 4 seconds memory limit per test 256 megabytes inp ...
- 【CF446C】DZY Loves Fibonacci Numbers (线段树 + 斐波那契数列)
Description 看题戳我 给你一个序列,要求支持区间加斐波那契数列和区间求和.\(~n \leq 3 \times 10 ^ 5, ~fib_1 = fib_2 = 1~\). Solut ...
- [莫队算法 线段树 斐波那契 暴力] Codeforces 633H Fibonacci-ish II
题目大意:给出一个长度为n的数列a. 对于一个询问lj和rj.将a[lj]到a[rj]从小到大排序后并去重.设得到的新数列为b,长度为k,求F1*b1+F2*b2+F3*b3+...+Fk*bk.当中 ...
- hdu 4983 线段树+斐波那契数
http://acm.hdu.edu.cn/showproblem.php?pid=4893 三种操作: 1 k d, 修改k的为值增加d 2 l r, 查询l到r的区间和 3 l r, 从l到r区间 ...
- Codeforces 316E3 线段树 + 斐波那切数列 (看题解)
最关键的一点就是 f[ 0 ] * a[ 0 ] + f[ 1 ] * a[ 1 ] + ... + f[ n - 1] * a[ n - 1] f[ 1 ] * a[ 0 ] + f[ 2 ] * ...
- Codeforces 446C - DZY Loves Fibonacci Numbers(斐波那契数列+线段树)
Codeforces 题目传送门 & 洛谷题目传送门 你可能会疑惑我为什么要写 *2400 的题的题解 首先一个很明显的想法是,看到斐波那契数列和 \(10^9+9\) 就想到通项公式,\(F ...
- HDU4099(斐波那契数列与字典树)
题目:Revenge of Fibonacci 题意:给出斐波那契数列的前k位,k不超过40,找出最小的正整数n,满足F(n)的前k位与给定数的前k位相同,斐波那契数列的项数不超过100000. 解析 ...
- coderfoces446c (斐波那契数列)
题目描述: 区间增值,但是每一项增加的值为Fi - l + 1,F[i]为斐波那契数列,求区间和? 考虑线段树,刚开始想用斐波那契数列的前n项和,可是推不出来,考虑到每个区间的增值序列都是一段斐波那契 ...
随机推荐
- Linux压缩解压 tar.gz格式的文件.查看tomcat是否运行
tar命令详解 -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用 ...
- APT组织跟踪与溯源
前言 在攻防演练中,高质量的蓝队报告往往需要溯源到攻击团队.国内黑产犯罪团伙.国外APT攻击. 红队现阶段对自己的信息保护的往往较好,根据以往溯源成功案例来看还是通过前端js获取用户ID信息.mysq ...
- matlab纹理映射之地球
%地球 cla reset; load topo; [x,y,z] = sphere(45); s = surface(x,y,z,'facecolor','texturemap','cdata',t ...
- vue项目 'node-sass'问题
Cannot find module 'node-sass' 解决办法: 运行命令:cnpm install node-sass@latest 即可解决,( 网络差的同学可以选择重新下载no-modu ...
- 【第四篇】-Git 工作区、暂存区和版本库之Spring Cloud直播商城 b2b2c电子商务技术总结
Git 工作区.暂存区和版本库 基本概念 我们先来理解下 Git 工作区.暂存区和版本库概念: 工作区:就是你在电脑里能看到的目录. 暂存区:英文叫 stage 或 index.一般存放在 .git ...
- Optional容器类
一.Optional 容器类:用于尽量避免空指针异常 方法 /* * Optional.of(T t) : 创建一个 Optional 实例 * Optional.empty() : 创建一个空的 O ...
- 六种多线程方法解决UI线程堵塞
http://blog.csdn.net/oyi319/article/details/6851371 一.六种多线程方法 .NET Framework2.0框架提供了至少4种方式实现多线程,它们是& ...
- 利用GetInvalidFileNameChars()得到有效的文件名
public static string GetValidName(string fileName) { foreach (char c in System.IO.Path.GetInvali ...
- 《挑战程序设计竞赛》——DFS
DFS(深度优先搜索) 简介 深度优先搜索(DFS,Depth-First Search)是搜索的手段之一.它从某个状态开始,不断的转移状态直到无法转移.然后退回到前一步的状态,继续转移到其他状态,如 ...
- 如何写出安全又可靠的PHP脚本
前言 咔咔目前所做的项目是一个saas系统,在开发新功能之后,需要为用户角色添加相应的权限,这时整个系统的所有用户都需要添加相应的权限. 因为以前系统的缺陷现在只能用脚本来处理这些工作,所以接下来咔咔 ...