YbtOJ#732-斐波那契【特征方程,LCT】
正题
题目链接:http://www.ybtoj.com.cn/contest/125/problem/2
题目大意
给出\(n\)个点的一棵树,以\(1\)为根,每个点有点权\(a_i\)。要求支持\(m\)次操作
- 修改一个修改一个节点的父节点
- 修改一条路径的权值为\(w\)
- 给出\(u\)询问\(Fbi(a_u)\)
- 给出\(u,v\),将路径\(u->v\)的点权排列好后设为\(b\)求
\]
其中\(Fbi(i)\)表示第\(i\)个斐波那契数。输出答案模\(998244353\)的值
\(1\leq n,m\leq 10^5,a_i,w\in[1,10^9]\)
解题思路
嗯这个斐波那契很麻烦,可以考虑一些用特征方程\(1-x-x^2=0\),可以得到斐波那契的通项公式
\]
为了方便上面\(\frac{\sqrt 5\pm 1}{2}\)分别记为\(X_0,X_1\)。
那么如果设\(c_i=X_0^{a_i},d_i=X_1^{a_i}\)的话我们要求的就是
\]
这个好像看起来好维护一点,不过首先我们要解决这个\(\sqrt 5\)的问题,因为其实\(\sqrt 5\)在模\(998244353\)意义下是没有值的,我们不能直接用二次剩余带入数字。
考虑维护一个类似于多项式的东西,每个数字记为二元组\((a,b)=a\sqrt 5+b\)。加减乘都很好搞,除法的话需要推导一下,
\]
\]
\]
解出来
\]
这样四则运算都搞定了,可以开始考虑如何在\(LCT\)上面维护了。
类似线段树的,设\(pro\)表示所有数乘积,\(pre/suf\)表示所有前/后缀乘积和,\(ans\)表示我们维护的答案,那么就可以合并两个东西了。\(LCT\)维护的时候顺便把单个的节点也合并进去就好了。
然后还剩下一个最麻烦的东西就是树链修改的时候我们需要快速算出连续\(x\)个\(u\)的信息。
\(pro\)很好搞就是\(u^x\),\(suf\)和\(pre\)就是一个简单的等比数列求和,上通项公式就好了。
\(ans\)比较麻烦,考虑每个\(u^i\)的个数答案就是
\]
\]
这样就可以在\(log\)时间复杂度以内合并了。
然后答案\(0\)次项一定是\(0\)的,所以输出\(\sqrt 5\)的项就好了。
时间复杂度\(O(n\log^2 n)\)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define ll long long
using namespace std;
const ll P=998244353,N=1e5+10;
struct node{
ll a,b;//a带√5
node(ll aa=0,ll bb=0)
{a=aa;b=bb;return;}
};
ll power(ll x,ll b=P-2){
ll ans=1;x%=P;
while(b){
if(b&1)ans=ans*x%P;
x=x*x%P;b>>=1;
}
return ans;
}
const node X((P+1)/2,(P+1)/2);
node operator+(node x,node y)
{return node((x.a+y.a)%P,(x.b+y.b)%P);}
node operator-(node x,node y)
{return node((x.a-y.a)%P,(x.b-y.b)%P);}
node operator*(node x,node y)
{return node((x.a*y.b+x.b*y.a)%P,(x.b*y.b+5*x.a*y.a)%P);}
node inv(node x){
ll tmp=power(x.b*x.b-5*x.a*x.a);
return node(-x.a,x.b)*node(0,tmp);
}
node power(node x,ll b){
node ans(0,1);
while(b){
if(b&1)ans=ans*x;
x=x*x;b>>=1;
}
return ans;
}
struct Tnode{
node ans,pre,suf,pro;
};
Tnode operator+(Tnode x,Tnode y){
Tnode w;
w.ans=x.ans+y.ans+x.suf*y.pre;
w.pre=x.pre+y.pre*x.pro;
w.suf=y.suf+x.suf*y.pro;
w.pro=x.pro*y.pro;return w;
}
struct SegTree{
ll fa[N],t[N][2],siz[N];
Tnode w[N];node v[N],lazy[N];
bool r[N],hlz[N];stack<ll> s;
bool Nroot(ll x)
{return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}
bool Direct(ll x)
{return t[fa[x]][1]==x;}
void Rev(ll x)
{swap(t[x][0],t[x][1]);swap(w[x].pre,w[x].suf);r[x]^=1;return;}
void PushUp(ll x){
siz[x]=siz[t[x][0]]+siz[t[x][1]]+1;
w[x]=(Tnode){v[x],v[x],v[x],v[x]};
if(t[x][0])w[x]=w[t[x][0]]+w[x];
if(t[x][1])w[x]=w[x]+w[t[x][1]];
return;
}
void Updata(ll x,node u){
ll s=siz[x];lazy[x]=v[x]=u;
node tmp=inv(node(0,1)-u);
hlz[x]=1; w[x].pro=power(u,s);
w[x].pre=w[x].suf=(u-w[x].pro*u)*tmp;
w[x].ans=(node(0,s)-w[x].pre)*u*tmp;
return;
}
void PushDown(ll x){
if(hlz[x]){
if(t[x][0])Updata(t[x][0],lazy[x]);
if(t[x][1])Updata(t[x][1],lazy[x]);
hlz[x]=0;
}
if(!r[x])return;
Rev(t[x][0]);Rev(t[x][1]);
r[x]=0;return;
}
void Rotate(ll x){
ll y=fa[x],z=fa[y];
ll xs=Direct(x),ys=Direct(y);
ll w=t[x][xs^1];
if(Nroot(y))t[z][ys]=x;
t[x][xs^1]=y;t[y][xs]=w;
if(w)fa[w]=y;fa[y]=x;fa[x]=z;
PushUp(y);PushUp(x);return;
}
void Splay(ll x){
ll y=x;s.push(x);
while(Nroot(y))y=fa[y],s.push(y);
while(!s.empty())PushDown(s.top()),s.pop();
while(Nroot(x)){
ll y=fa[x];
if(!Nroot(y))Rotate(x);
else if(Direct(x)==Direct(y))
Rotate(y),Rotate(x);
else Rotate(x),Rotate(x);
}
return;
}
void Access(ll x){
for(ll y=0;x;y=x,x=fa[x])
Splay(x),t[x][1]=y,PushUp(x);
return;
}
void MakeRoot(ll x)
{Access(x);Splay(x);Rev(x);return;}
void Link(ll x,ll y){
MakeRoot(1);Access(x);Splay(x);
fa[t[x][0]]=0;t[x][0]=0;PushUp(x);
fa[x]=y;return;
}
ll Split(ll x,ll y){
MakeRoot(x);Access(y);Splay(y);
return (w[y].ans.a+P)%P*2%P;
}
void Change(ll x,ll y,node val){
MakeRoot(x);Access(y);Splay(y);
Updata(y,val);return;
}
}T;
ll n,m;
signed main()
{
// freopen("fibonacci.in","r",stdin);
// freopen("fibonacci.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++){
ll x;scanf("%lld",&x);
T.v[i]=power(X,x);
T.PushUp(i);
}
for(ll i=2;i<=n;i++)
scanf("%lld",&T.fa[i]);
while(m--){
ll op,u,v,w;
scanf("%lld",&op);
if(op==1){
scanf("%lld%lld",&u,&v);
T.Link(u,v);
}
else if(op==2){
scanf("%lld%lld%lld",&u,&v,&w);
T.Change(u,v,power(X,w));
}
else if(op==3){
scanf("%lld",&u);
printf("%lld\n",T.Split(u,u));
}
else if(op==4){
scanf("%lld%lld",&u,&v);
printf("%lld\n",T.Split(u,v));
}
}
return 0;
}
YbtOJ#732-斐波那契【特征方程,LCT】的更多相关文章
- 洛谷P1720 月落乌啼算钱 题解 斐波那契数列/特征方程求解
题目链接:https://www.luogu.com.cn/problem/P1720 题目描述: 给你一个公式 ,求对应的 \(F_n\) . 解题思路: 首先不难想象这是一个斐波那契数列,我们可以 ...
- 几种复杂度的斐波那契数列的Java实现
一:斐波那契数列问题的起源 13世纪初期,意大利数论家Leonardo Fibonacci在他的著作Liber Abaci中提出了兔子的繁殖问题: 如果一开始有一对刚出生的兔子,兔子的长大需要一个月, ...
- CF717A Festival Organization(第一类斯特林数,斐波那契数列)
题目大意:求 $\sum\limits_{n=l}^{r}\dbinom{f_n}{k}\bmod 10^9+7$.其中 $f_n$ 是长度为 $n$ 的 $01$ 序列中,没有连续两个或超过两个 $ ...
- Computational Complexity of Fibonacci Sequence / 斐波那契数列的时空复杂度
Fibonacci Sequence 维基百科 \(F(n) = F(n-1)+F(n-2)\),其中 \(F(0)=0, F(1)=1\),即该数列由 0 和 1 开始,之后的数字由相邻的前两项相加 ...
- [每日一题2020.06.14]leetcode #70 爬楼梯 斐波那契数列 记忆化搜索 递推通项公式
题目链接 题意 : 求斐波那契数列第n项 很简单一道题, 写它是因为想水一篇博客 勾起了我的回忆 首先, 求斐波那契数列, 一定 不 要 用 递归 ! 依稀记得当年校赛, 我在第一题交了20发超时, ...
- P5110 块速递推-光速幂、斐波那契数列通项
P5110 块速递推 题意 多次询问,求数列 \[a_i=\begin{cases}233a_{i-1}+666a_{i-2} & i>1\\ 0 & i=0\\ 1 & ...
- C#求斐波那契数列第30项的值(递归和非递归)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- python迭代器实现斐波拉契求值
斐波那契数列(Fibonacci sequence),又称黄金分割数列,也称为"兔子数列":F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*).例 ...
- Ural 1225. Flags 斐波那契DP
1225. Flags Time limit: 1.0 secondMemory limit: 64 MB On the Day of the Flag of Russia a shop-owner ...
- 斐波拉契数列加强版——时间复杂度O(1),空间复杂度O(1)
对于斐波拉契经典问题,我们都非常熟悉,通过递推公式F(n) = F(n - ) + F(n - ),我们可以在线性时间内求出第n项F(n),现在考虑斐波拉契的加强版,我们要求的项数n的范围为int范围 ...
随机推荐
- mysql优化: 内存表和临时表
由于直接使用临时表来创建中间表,其速度不如人意,因而就有了把临时表建成内存表的想法.但内存表和临时表的区别且并不熟悉,需要查找资料了.一开始以为临时表是创建后存在,当连接断开时临时表就会被删除,即临时 ...
- 九:Decorator设计模式
二.使用Decorator设计模式增强request对象 Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrappe ...
- C 静态存储动态存储
首先,我们可以把程序所占的内存空间分为三个部分:(可以根据静态资源区.栈区.堆区来划分) 静态存储:程序运行期间由系统分配固定得到存储空间(栈): 动态存储:开发者根据自身需要进行动态分配的存储空间( ...
- 初始C3P0连接池
C3P0连接池只需要一个jar包: 其中我们可以看到有三个jar包: 属于C3P0的jar包只有一个,另外两个是测试时使用的JDBC驱动:一个是mysql的,一个是oracle的: 可以看到在src下 ...
- rabbitMq队列长度限制
x-max-length:队列最大容纳消息条数 大于设置条数的时候会把,消息队列头部(先进入消息)的消息移除 x-max-length-bytes:队列最大容量消息内存容量服务端限流内存控制流量:40 ...
- 高德地图——2D转换3D
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script ty ...
- Learning ROS: Managing System dependencies
Download and install the system dependencies for turtlesim: roscd turtlesim cat package.xml rosdep i ...
- 解决->maven下载失败bug
一.前言: 经过一个下午的奋斗(谷歌,视频...重装)后终,于暂时解决了上一篇文章中的bug 传送门:https://blog.csdn.net/weixin_44092288/article/det ...
- 爱思助手备份 iPhone 时没有设置密码,恢复备份时需要密码的问题
i4.cn 备份时 iPhone 上登陆的 Apple ID 曾经设置过备份密码,这个密码就是恢复备份时需要输入的密码!
- 洛谷P3130 haybalesCounting Haybale P 题解
题目 [USACO15DEC]haybalesCounting Haybale P 题解 最近刚刚自学了线段树这个数据结构,恰巧做到了这道线段树的模板题.其实也没有什么好多说的,接触过线段树的大犇肯定 ...