zoukankan      html  css  js  c++  java
  • 一本通 高手训练 1765 树上斐波那契 矩阵乘法 树链剖分

    LINK:树上斐波那契

    这道题关于广义斐波那契以及斐波那契的性质的一个题目。

    (f_a)表示斐波那契数列的第a项 那么有(f_{a+b}=f_{a-1}cdot f_b+f_{a}cdot f_{b+1})

    关于证明 可以采用数学归纳法。挺容易的。

    这道题是x子树内增加 (f_{k+D})其中k为常数 D为x子树内的点距x的距离。

    容易转换为 (f_{k+d_u-d_x}) 套上面的斐波那契类似于结论的等式就可以发现每次是单点增加定值可以直接维护和了。

    值得一提的是 由于k很大 所以需要矩阵乘法。

    还有就是 下表为负的情况 搞出广义斐波那契 使用即可。

    还是比较好码的题目。

    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000000000ll
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007
    #define S second 
    #define F first
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define ull unsigned long long
    #define ui unsigned
    #define EPS 1e-8
    #define mod 1000000007
    #define sq sqrt
    #define zz p<<1
    #define yy p<<1|1
    #define l(p) t[p].l
    #define r(p) t[p].r
    #define sum(p) t[p].sum
    #define tag1(p) t[p].tag1
    #define tag2(p) t[p].tag2
    #define cnt1(p) t[p].cnt1
    #define cnt2(p) t[p].cnt2
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    inline ll Read()
    {
        RE ll x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=100010;
    int n,m,cnt,id,len;
    int fa[MAXN],sz[MAXN],son[MAXN],d[MAXN],top[MAXN],pos[MAXN],dfn[MAXN];
    int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],f[MAXN],df[MAXN];
    ll a[2][2],cc[2][2];
    inline void add(int x,int y)
    {
    	ver[++len]=y;nex[len]=lin[x];lin[x]=len;
    	ver[++len]=x;nex[len]=lin[y];lin[y]=len;
    }
    struct wy//线段树
    {
    	int l,r;
    	int sum;
    	int cnt1,cnt2;
    	int tag1,tag2;
    }t[MAXN<<2];
    struct jl//FiB
    {
    	int f[2];
    	jl(){f[0]=0;f[1]=1;}
    	inline jl calc(ll w)
    	{
    		jl c;
    		a[0][0]=0;a[0][1]=a[1][0]=a[1][1]=1;
    		while(w)
    		{
    			if(w&1)
    			{
    				ll w1=0,w2=0;
    				w1=(w1+c.f[0]*a[0][0])%mod;
    				w2=(w2+c.f[0]*a[0][1])%mod;
    				w1=(w1+c.f[1]*a[1][0])%mod;
    				w2=(w2+c.f[1]*a[1][1])%mod;
    				c.f[0]=w1;c.f[1]=w2;
    			}
    			w=w>>1;
    			rep(0,1,i)rep(0,1,j)rep(0,1,k)
    				cc[i][j]=(cc[i][j]+a[i][k]*a[k][j])%mod;
    			rep(0,1,i)rep(0,1,j)a[i][j]=cc[i][j],cc[i][j]=0;
    		}
    		return c;
    	}
    }s,ww;
    inline void dfs(int x,int ff)
    {
    	fa[x]=ff;d[x]=d[ff]+1;sz[x]=1;
    	go(x)if(tn!=ff)
    	{
    		dfs(tn,x);
    		if(sz[tn]>sz[son[x]])son[x]=tn;
    		sz[x]+=sz[tn];
    	}
    }
    inline void dp(int x,int ff)
    {
    	top[x]=ff;dfn[x]=++id;pos[id]=x;
    	if(!son[x])return;
    	dp(son[x],ff);
    	go(x)if(tn!=son[x]&&tn!=fa[x])dp(tn,tn);
    }
    inline void build(int p,int l,int r)
    {
    	l(p)=l;r(p)=r;
    	if(l==r)
    	{
    		cnt1(p)=(cnt1(p)+f[d[pos[l]]-1])%mod;
    		cnt2(p)=(cnt2(p)+f[d[pos[l]]])%mod;
    		return;
    	}
    	int mid=(l(p)+r(p))>>1;
    	build(zz,l,mid);
    	build(yy,mid+1,r);
    	cnt1(p)=(cnt1(zz)+cnt1(yy))%mod;
    	cnt2(p)=(cnt2(zz)+cnt2(yy))%mod;
    }
    inline void pushdown(int p)
    {
    	tag1(zz)=(tag1(zz)+tag1(p))%mod;
    	tag1(yy)=(tag1(yy)+tag1(p))%mod;
    	tag2(zz)=(tag2(zz)+tag2(p))%mod;
    	tag2(yy)=(tag2(yy)+tag2(p))%mod;
    	sum(zz)=(sum(zz)+(ll)tag1(p)*cnt1(zz))%mod;
    	sum(yy)=(sum(yy)+(ll)tag1(p)*cnt1(yy))%mod;
    	sum(zz)=(sum(zz)+(ll)tag2(p)*cnt2(zz))%mod;
    	sum(yy)=(sum(yy)+(ll)tag2(p)*cnt2(yy))%mod;
    	tag1(p)=tag2(p)=0;
    }
    inline void change(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))
    	{
    		tag1(p)=(tag1(p)+ww.f[0])%mod;
    		tag2(p)=(tag2(p)+ww.f[1])%mod;
    		sum(p)=(sum(p)+(ll)ww.f[0]*cnt1(p))%mod;
    		sum(p)=(sum(p)+(ll)ww.f[1]*cnt2(p))%mod;
    		return;
    	}
    	if(tag1(p)||tag2(p))pushdown(p);
    	int mid=(l(p)+r(p))>>1;
    	if(l<=mid)change(zz,l,r);
    	if(r>mid)change(yy,l,r);
    	sum(p)=(sum(zz)+sum(yy))%mod;
    }
    inline int ask(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))return sum(p);
    	int mid=(l(p)+r(p))>>1;
    	if(tag1(p)||tag2(p))pushdown(p);
    	if(r<=mid)return ask(zz,l,r);
    	if(l>mid)return ask(yy,l,r);
    	return (ask(zz,l,r)+ask(yy,l,r))%mod;
    }
    inline int Task(int x,int y)
    {
    	int fx=top[x],fy=top[y];
    	int ans=0;
    	while(fx!=fy)
    	{
    		if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
    		ans=(ans+ask(1,dfn[fx],dfn[x]))%mod;
    		x=fa[fx];fx=top[x];
    	}
    	if(d[x]<d[y])swap(x,y);
    	ans=(ans+ask(1,dfn[y],dfn[x]))%mod;
    	return ans;
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(n);get(m);df[1]=1;f[1]=1;
    	rep(2,n,i)add(i,read()),f[i]=(f[i-2]+f[i-1])%mod,df[i]=(df[i-2]-df[i-1]+mod)%mod;
    	dfs(1,0);dp(1,1);build(1,1,n);
    	rep(1,m,i)
    	{
    		char ch=getc();
    		while(ch!='Q'&&ch!='U')ch=getc();
    		if(ch=='U')
    		{
    			int get(x);ll k;k=Read()-d[x];
    			if(k<=0)
    			{
    				ww.f[0]=df[-k];
    				if(k==0)ww.f[1]=f[1];
    				else ww.f[1]=df[-(k+1)];
    			}
    			else ww=s.calc(k);
    			change(1,dfn[x],dfn[x]+sz[x]-1);
    		}
    		else put(Task(read(),read()));
    	}
    	return 0;
    }
    
  • 相关阅读:
    安装vue-cli最新版后,无法使用console方法的解决办法
    使用yarn 安装 vue.js devtools(2020.1.6)
    在路由切换后 将滚动条置顶
    标签页 elementUI 激活时的颜色 怎样改 很坑爹!
    页面滚动鼠标产生动画 wow.js 在vue中
    CSS多行文本溢出隐藏,显示省略号
    ... 扩展运算符
    this的指向的一些问题
    用for循环和用for-in循环遍历数组最大的区别
    数组的indexOf、forEach、map、filter、方法的理解
  • 原文地址:https://www.cnblogs.com/chdy/p/12852821.html
Copyright © 2011-2022 走看看