FIBTREE - Fibonacci Numbers on Tree

斐波那契数列的通项公式

而在膜1e9+9的条件下,有一个与sqrt(5)等价的数,这个数就是383008016。

因此上式可以改写成276601605*(((1+383008016)*500000005)^n-((1-383008016)*500000005)^n))

即a_n=276601605*(691504013^n-308495997^n)

发现两个等比数列的和,这样就能用线段树打标记,然后O(1)求值了。

第二个询问用树剖搞搞就好了。

第三个询问有三种情况。当x==y时输出size[root],当y是x的祖先时,结果为size[root]-size[y]+1,否则为size[y]。

第四个询问是在刻意增加难度。需要将线段树可持久化。

不想写了,感觉内存好像不能再开了。果然这种题就应该只用嘴巴做。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pll pair<LL,LL>
#define mkp make_pair
#define X first
#define Y second
#define N 100//005
#define NN 220//00000
#define M 1000000009LL
#define A1 691504013LL
#define A2 308495997LL
#define A3 691504012LL
#define A4 308495996LL
#define A5 308495995LL
#define A6 691504011LL
#define A7 276601605LL
LL n,ans;
LL pw1[N],pw2[N],pw3[N],pw4[N];
LL he[N],ne[N<<1],to[N<<1],tot;
LL dep[N],sz[N],son[N],dad[N],pre[N],dfn[N],nfd[N],cnt;
LL rt[N],now,las,m,wz[N],id,a1[NN],a2[NN],a3[NN],a4[NN],sum[NN],lz1[NN],lz2[NN],lz3[NN],lz4[NN],lc[NN],rc[NN];
LL read(){
	LL x=0;char ch=G;
	while(ch<48||ch>57)ch=G;
	for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
	return x; 
}
char readc(){
	char ch=G;
	while(ch<65||ch>90)ch=G;
	return ch;
}
LL add(LL x,LL y){
	LL rtn=x+y;
	if(rtn>=M)rtn-=M;
	return rtn;
}
LL mul(LL x,LL y){
	return x*y%M;
}
void add2(LL x,LL y){
	to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
void DFS1(LL x){
	LL y,i;dep[x]=dep[pre[x]]+1;sz[x]=1;
	for(i=he[x];i;i=ne[i])if((y=to[i])!=pre[x]){
		pre[y]=x;DFS1(y);
		if(sz[y]>sz[son[x]])son[x]=y;sz[x]+=sz[y];
	}
}
void DFS2(LL x){
	LL y,i;dad[x]=son[pre[x]]==x?dad[pre[x]]:x;nfd[dfn[x]=++cnt]=x;
	if(son[x])DFS2(son[x]);
	for(i=he[x];i;i=ne[i])if(!dfn[y=to[i]])
		DFS2(y);
}
LL lca(LL x,LL y){
	LL fx=dad[x],fy=dad[y];
	while(fx!=fy)
		if(dep[fx]>dep[fy])fx=dad[x=pre[fx]];
		else fy=dad[y=pre[fy]];
	return dep[x]<dep[y]?x:y;
}
LL cal1(LL a,LL x){
	return mul(a,mul(add(pw1[x],M-1),A1));
}
LL cal2(LL a,LL x){
	return mul(a,mul(add(pw2[x],M-1),A2));
}
LL cal3(LL a,LL x){
	return mul(a,mul(add(pw3[x],M-1),A5));
}
LL cal4(LL a,LL x){
	return mul(a,mul(add(pw4[x],M-1),A6));
}
void up(LL num,LL x){
	sum[num]=add(add(sum[lc[num]],sum[rc[num]]),add(add(cal1(lz1[num],x),cal2(lz2[num],x)),add(cal3(lz3[num],x),cal4(lz4[num],x))));
}
void ins1(LL L,LL R,LL x,LL l,LL r,LL&num,LL old){
	a1[num=++id]=a1[old];a2[num]=a2[old];sum[num]=sum[old];
	if(L<=l&&r<=R){
		LL tmp1=pw1[x+l-L],tmp2=pw2[x+l-L];
		a1[num]=add(a1[num],tmp1);
		lz1[num]=add(a1[num],tmp1);
		a2[num]=add(a2[num],tmp2);
		lz2[num]=add(a2[num],tmp2);
		sum[num]=add(sum[num],add(cal1(tmp1,r-l+1),cal2(tmp2,r-l+1)));
		return;
	}
	LL mid=l+r>>1;
	if(L<=mid)ins1(L,R,x,l,mid,lc[num],lc[old]);
	else lc[num]=lc[old];
	if(R>mid) ins1(L,R,x,mid+1,r,rc[num],rc[old]);
	else rc[num]=rc[old];
	up(num,r-l+1);
}
void ins2(LL L,LL R,LL x,LL l,LL r,LL&num,LL old){
	a3[num=++id]=a3[old];a4[num]=a4[old];sum[num]=sum[old];
	if(L<=l&&r<=R){
		LL tmp3=pw3[x+l-L],tmp4=pw4[x+l-L];
		a3[num]=add(a3[num],tmp3);
		lz3[num]=add(a3[num],tmp3);
		a4[num]=add(a4[num],tmp4);
		lz4[num]=add(a4[num],tmp4);
		sum[num]=add(sum[num],add(cal3(tmp3,r-l+1),cal4(tmp4,r-l+1)));
		return;
	}
	LL mid=l+r>>1;
	if(L<=mid)ins2(L,R,x,l,mid,lc[num],lc[old]);
	else lc[num]=lc[old];
	if(R>mid) ins2(L,R,x,mid+1,r,rc[num],rc[old]);
	else rc[num]=rc[old];
	up(num,r-l+1);
}
void query(LL L,LL R,LL l,LL r,LL num){
	if(!num)return;
	if(L==l&&r==R){
		ans=add(ans,sum[num]);return;
	}
	ans=add(ans,add(add(cal1(mul(lz1[num],pw1[L-l+1]),R-L+1),cal2(mul(lz2[num],pw2[L-l+1]),R-L+1)),add(cal3(mul(lz3[num],pw3[L-l+1]),R-L+1),cal4(mul(lz4[num],pw4[L-l+1]),R-L+1))));
	LL mid=l+r>>1;
	if(L<=mid)query(L,min(mid,R),l,mid,lc[num]);
	if(R>mid)query(max(mid+1,L),R,mid+1,r,rc[num]);
}
int main(){
	LL i,Q,x,y,z,fx,fy,a;char ch;
	n=read();Q=read();
	pw1[0]=pw2[0]=pw3[0]=pw4[0]=1;
	rep(i,1,n)pw1[i]=mul(pw1[i-1],A1),pw2[i]=mul(pw2[i-1],A2),pw3[i]=mul(pw3[i-1],A3),pw4[i]=mul(pw4[i-1],A4);
	rep(i,2,n){
		x=read();y=read();add2(x,y);add2(y,x);
	}
	DFS1(1);DFS2(1);
	while(Q--){
		if((ch=readc())=='Q'){
			ch=readc();x=read()^ans;y=read();
			ans=0;
			if(ch=='S'){
				if(x==y)ans=sum[rt[las]];
				else{
					for(fx=dad[x],fy=dad[y];dep[x]>=dep[y]&&fx!=fy;fx=dad[x=pre[fx]]);
					query(dfn[y],dfn[y]+sz[y]-1,1LL,n,rt[las]);
					if(dep[x]>=dep[y])ans=add(sum[rt[las]],M-ans);
				}
			}
			else{
				z=lca(x,y);
				for(fx=dad[x];dep[fx]>dep[z];fx=dad[x=pre[fx]])
					query(dfn[fx],dfn[x],1LL,n,rt[las]);
				if(dfn[z]<dfn[x])query(dfn[z]+1,dfn[x],1LL,n,rt[las]);
				for(fy=dad[y];dep[fy]>dep[z];fy=dad[y=pre[fy]])
					query(dfn[fy],dfn[y],1,n,rt[las]);
				query(dfn[z],dfn[y],1LL,n,rt[las]);
			}
			printf("%lld\n",ans=mul(ans,A7));
		}
		else if(ch=='A'){
			x=read()^ans;y=read();z=lca(x,y);a=0;
			for(fx=dad[x];dep[fx]>dep[z];fx=dad[x=pre[fx]]){
				a+=dfn[x]-dfn[fx]+1;
				ins2(dfn[fx],dfn[x],a,1LL,n,rt[++now],rt[las]);las=now;
			}
			if(dfn[z]<dfn[x]){
				a+=dfn[x]-dfn[z];
				ins2(dfn[z]+1,dfn[x],a,1LL,n,rt[++now],rt[las]);las=now;
			}
			a+=dep[y]-dep[x]+2;
			for(fy=dad[y];dep[fy]>dep[z];fy=dad[y=pre[fy]]){
				a-=dfn[y]-dfn[fy]+1;
				ins1(dfn[fy],dfn[y],a,1LL,n,rt[++now],rt[las]);las=now;
			}
			a-=dfn[y]-dfn[z]+1;
			ins1(dfn[z],dfn[y],a,1LL,n,rt[++now],rt[las]);
			wz[++m]=las=now;
		}
		else las=wz[read()^ans];
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值