Codechef :Fibonacci Numbers on Tree/FIBTREE(主席树)

本文介绍了一种使用链剖与可持久化线段树解决区间加等比数列问题的方法,通过矩阵或二次剩余进行计算,特别适用于处理比相同的区间更新和查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

题解:
这道题用二次剩余或者矩阵都可以做。

相当于链剖之后维护一个区间加等比数列的可持久化线段树。 因为比相同,所以很好维护。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=2e5+50, mod=1e9+9, base=383008016;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (LL)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
inline int inv(int a) {return power(a,mod-2);}
const int base1=mul(base+1,inv(2)), base2=mul(dec(1,base),inv(2)), iv1=inv(base1), iv2=inv(base2), iv=inv(base);

int n,m,ind,lastans,pw1[N],pw2[N];
int fa[N],dep[N],sze[N],son[N],top[N],dfn[N];
vector <int> edge[N];
struct ST {
	int bs,s[N],pw[N];
	int rt[N],lc[N*100],rc[N*100],sum[N*100],d[N*100],tot;
	inline void build(int &k,int l,int r) {
		k=++tot; if(l==r) return;
		int mid=(l+r)>>1;
		build(lc[k],l,mid);
		build(rc[k],mid+1,r);
	}
	inline void upt(int k,int len) {
		sum[k]=add(sum[lc[k]],sum[rc[k]]);
		sum[k]=add(sum[k],mul(dec(s[len],1),d[k]));
	}
	inline void copy(int &x,int y) {x=++tot; d[x]=d[y]; sum[x]=sum[y]; lc[x]=lc[y]; rc[x]=rc[y];}
	inline void inc(int &k,int l,int r,int L,int R,int v) {
		copy(k,k);
		if(L==l && r==R) {d[k]=add(d[k],v); upt(k,r-l+1); return;}
		int mid=(l+r)>>1;
		if(R<=mid) inc(lc[k],l,mid,L,R,v);
		else if(L>mid) inc(rc[k],mid+1,r,L,R,v);
		else inc(lc[k],l,mid,L,mid,v), inc(rc[k],mid+1,r,mid+1,R,mul(v,pw[mid+1-L]));
		upt(k,r-l+1); return;
	}
	inline int ask(int &k,int l,int r,int L,int R) {
		if(L==l && r==R) return sum[k];
		int res=mul(d[k],dec(s[R-l+1],s[L-l]));
		int mid=(l+r)>>1;
		if(R<=mid) return add(res,ask(lc[k],l,mid,L,R));
		else if(L>mid) return add(res,ask(rc[k],mid+1,r,L,R));
		else return add(res,add(ask(lc[k],l,mid,L,mid),ask(rc[k],mid+1,r,mid+1,R)));
	}
	inline void init() {
		pw[0]=s[0]=1;
		for(int i=1;i<=n+1;i++) s[i]=mul(s[i-1],bs), ++s[i], pw[i]=mul(pw[i-1],bs);
		build(rt[0],1,n);
	}
} st[4];

inline int lca(int x,int y) {
	while(top[x]^top[y]) 
		(dep[top[x]]>dep[top[y]]) ? (x=fa[top[x]]) : (y=fa[top[y]]);
	return (dep[x]>dep[y]) ? y : x;
}
inline void dfs(int x,int f) {
	sze[x]=1; dep[x]=dep[f]+1; fa[x]=f;
	for(auto v:edge[x]) if(v^f) {
		dfs(v,x); sze[x]+=sze[v];
		if(sze[son[x]]<sze[v]) son[x]=v;
	}
}
inline void dfs_top(int x,int f) {
	dfn[x]=++ind;
	if(son[x]) top[son[x]]=top[x], dfs_top(son[x],x);
	for(auto v:edge[x]) if(v^f && v^son[x]) top[v]=v, dfs_top(v,x);
}
inline void init() {
	n=rd(), m=rd();
	st[0].bs=inv(base1);
	st[1].bs=inv(base2);
	st[2].bs=base1;
	st[3].bs=base2;
	for(int i=0;i<=3;i++) st[i].init();
	for(int i=1;i<n;i++) {
		int x=rd(), y=rd();
		edge[x].push_back(y);
		edge[y].push_back(x);
	} dfs(1,0); top[1]=1; dfs_top(1,0);
	pw1[0]=1; for(int i=1;i<=n+1;i++) pw1[i]=mul(pw1[i-1],base1);
	pw2[0]=1; for(int i=1;i<=n+1;i++) pw2[i]=mul(pw2[i-1],base2);
}

int tim;
inline int ask(int l,int r) {
	int ans=0;
	ans=add(ans,st[0].ask(st[0].rt[tim],1,n,l,r));
	ans=dec(ans,st[1].ask(st[1].rt[tim],1,n,l,r));
	ans=add(ans,st[2].ask(st[2].rt[tim],1,n,l,r));
	ans=dec(ans,st[3].ask(st[3].rt[tim],1,n,l,r));
	return ans;
}

int main() {
	init();	
	for(int i=1;i<=m;i++) {
		tim=i;
		char ch=nc(); while(!isalpha(ch)) ch=nc();
		if(ch=='A') {
			for(int j=0;j<=3;j++) st[j].rt[i]=st[j].rt[i-1];
			int x=rd()^lastans, y=rd(), l=lca(x,y);
			int u=x, det=0;
			while(dep[u]>=dep[l]) {
				int f=top[u]; if(dep[f]<dep[l]) f=l;
				det+=dep[u]-dep[f]+1;
				st[0].inc(st[0].rt[i],1,n,dfn[f],dfn[u],pw1[det+1]);
				st[1].inc(st[1].rt[i],1,n,dfn[f],dfn[u],pw2[det+1]);
				u=fa[f];
			} 
			u=y;
			while(dep[u]>=dep[l]) {
				int f=top[u]; if(dep[f]<dep[l]) f=l;
				int kth=det+dep[f]-dep[l];
				st[2].inc(st[2].rt[i],1,n,dfn[f],dfn[u],pw1[kth-1]);
				st[3].inc(st[3].rt[i],1,n,dfn[f],dfn[u],pw2[kth-1]);
				u=fa[f];
			}
			st[2].inc(st[2].rt[i],1,n,dfn[l],dfn[l],mod-pw1[det-1]);
			st[3].inc(st[3].rt[i],1,n,dfn[l],dfn[l],mod-pw2[det-1]);
		} else if(ch=='R') {
			int x=rd()^lastans;
			for(int j=0;j<=3;j++) st[j].rt[i]=st[j].rt[x];
		} else if(nc()=='S') {
			for(int j=0;j<=3;j++) st[j].rt[i]=st[j].rt[i-1];
			int x=rd()^lastans, y=rd(), ans=0; swap(x,y);
			if(x==y) ans=ask(1,n);
			else if(!(dfn[y]>dfn[x] && dfn[y]<dfn[x]+sze[x])) ans=ask(dfn[x],dfn[x]+sze[x]-1);
			else {
				int last=y;
				while(top[y]^top[x]) last=top[y], y=fa[top[y]];
				y=(y!=x) ? son[x] : last;
				ans=dec(ask(1,n),ask(dfn[y],dfn[y]+sze[y]-1));
			} printf("%d\n",lastans=mul(ans,iv));
		} else {
			for(int j=0;j<=3;j++) st[j].rt[i]=st[j].rt[i-1];
			int x=rd()^lastans, y=rd(), l=lca(x,y);
			int u=x, ans=0;
			while(dep[u]>=dep[l]) {
				int f=top[u]; if(dep[f]<dep[l]) f=l;
				ans=add(ans,ask(dfn[f],dfn[u]));
				u=fa[f];
			} 
			u=y;
			while(dep[u]>=dep[l]) {
				int f=top[u]; if(dep[f]<dep[l]) f=l;
				ans=add(ans,ask(dfn[f],dfn[u]));
				u=fa[f];
			} ans=dec(ans,ask(dfn[l],dfn[l]));
			printf("%d\n",lastans=mul(ans,iv));
		} 
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值