本題謝絕轉載
五十分很送,七十分也水。
斐波那契數列有兩個性質:
1.兩個斐波那契數列相加,還是斐波那契數列。
2.斐波那契數列斷開,還是斐波那契數列。
一個點的權值,只與首項的值(也就是起點的a和b,但是這個點的權值只表現出a)以及首項到它的距離有關。
對於70分,首項位置確定,它到所有點的距離可以預處理。
只需要維護首項的值,建立兩個樹狀數組,下標是到起點的距離+1(因爲update(0,val)以及其他一些東西會出現問題,所以下標統統+1),值是a和b。修改時在1加a加b,在m+2減a減b。詢問時getsum(dist+1)即可得到首項。
對於100分,用出題者的話說,“不停地換點做修改,很明顯是點分治啦”。
於是,動態點分治。
每一次在點分樹往上爬,相當於把斐波那契數列截斷,算出新的首項和距離在該點更新。爲了避免重複計算,需要記錄是從哪個方向爬過來的,新開樹狀數組計算重複,詢問時減掉即可。
詢問就是在該點往上爬,算出它自己以及點分樹上它的父親對它的影響。
後話:
自學了點分治,前前後後花了一個多星期的零散時間寫這道題。
修了各種bug,研究vector數組套結構體vector。
順便試了一下類似於RMQ求LCA的東西。原理:https://www.cnblogs.com/scau20110726/archive/2013/05/26/3100812.html
打出了有史以來最長的代碼,下面附的還是精簡版。
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
const int Mod=1e9+7;
struct BIT {
int size;
vector<LL> c1,c2;
inline void init(int dist) {
size=dist+1;
c1.resize(size+1);
c2.resize(size+1);
}
inline int lowbit(int x) {
return x&-x;
}
inline void update(int x,LL val1,LL val2) {
if (val1<0) val1+=Mod;
if (val2<0) val2+=Mod;
for (;x<=size;x+=lowbit(x)) {
c1[x]+=val1;c2[x]+=val2;
if (c1[x]>=Mod) c1[x]-=Mod;
if (c2[x]>=Mod) c2[x]-=Mod;
}
}
inline void getsum(int x,LL &a,LL &b) {
a=b=0;
for (;x;x-=lowbit(x)) {
a+=c1[x];b+=c2[x];
if (a>=Mod) a-=Mod;
if (b>=Mod) b-=Mod;
}
}
};
vector<BIT> node[200005];
int head[200005],vet[400005],nxt[400005],num;
int Dep[200005],R[400005],F[200005],st[400005][19],ti,pow2[19];
int sz[200005],mxs[200005],root,mxson;
int fa[200005],idx[200005];
LL fib1[200005],fib2[200005];
bool vis[200005];
int n,q;
void addedge(int x,int y) {
num++;vet[num]=y;nxt[num]=head[x];head[x]=num;
num++;vet[num]=x;nxt[num]=head[y];head[y]=num;
}
inline int read() {
char ch=0;int sum=0;
while (ch<'0' || ch>'9') ch=getchar();
while (ch<='9' && ch>='0') sum=sum*10+ch-'0',ch=getchar();
return sum;
}
void dfs(int x,int dep,int ff) {
Dep[x]=dep;
R[++ti]=dep;
F[x]=ti;
for (int e=head[x];e;e=nxt[e]) {
if (vet[e]==ff) continue;
int v=vet[e];
dfs(v,dep+1,x);
R[++ti]=dep;
}
}
void ST(int len) {
int K=(int)(log((double)len)/log(2.0));
for (int i=1;i<=len;i++) st[i][0]=R[i];
for (int i=1;i<=K;i++) {
for (int j=1;j+pow2[i]-1<=len;j++) {
st[j][i]=min(st[j][i-1],st[j+pow2[i-1]][i-1]);
}
}
}
int getdist(int u,int v) {
int x=F[u],y=F[v];
if (x>y) swap(x,y);
int K=(int)(log((double)y-x+1)/log(2.0));
return Dep[u]+Dep[v]-2*min(st[x][K],st[y-pow2[K]+1][K]);
}
void getroot(int x,int ff,int tt) {
sz[x]=1;mxs[x]=0;
for (int e=head[x];e;e=nxt[e]) {
int v=vet[e];
if (v==ff || vis[v]) continue;
getroot(v,x,tt);
sz[x]+=sz[v];
mxs[x]=max(mxs[x],sz[v]);
}
mxs[x]=max(mxs[x],tt-sz[x]);
if (mxs[x]<mxs[root]) root=x,mxson=mxs[x];
}
void solve(int x,int tot) {
vis[x]=true;int son=0,mx=mxson;
for (int e=head[x];e;e=nxt[e]) {
if (!vis[vet[e]]) {
root=0;
int tt=sz[vet[e]];
if (tt>sz[x]) tt=tot-sz[x];
getroot(vet[e],x,tt);
fa[root]=x;
idx[root]=++son;
solve(root,tt);
}
}
node[x].resize(son+1);
if (!son) {
node[x][0].init(0);
return;
}
for (int i=0;i<=son;i++) node[x][i].init(mx);
}
inline LL getfib(LL a,LL b,int dist) {
return (fib1[dist]*a+fib2[dist]*b)%Mod;
}
inline void modify(int x,int m,LL a,LL b) {
int u=x,ff=fa[u];
node[u][0].update(1,a,b);
if (node[u][0].size>=m+2) {
node[u][0].update(m+2,-a,-b);
}
while (ff) {
int dist=getdist(x,ff);
if (dist<=m) {
LL tmp1=getfib(a,b,dist),tmp2=getfib(a,b,dist+1);
dist=m-dist;
node[ff][0].update(1,tmp1,tmp2);
node[ff][idx[u]].update(1,tmp1,tmp2);
if (dist+2<=node[fa[u]][0].size) {
node[ff][0].update(dist+2,-tmp1,-tmp2);
node[ff][idx[u]].update(dist+2,-tmp1,-tmp2);
}
}
u=ff;
ff=fa[u];
}
}
inline LL query(int x) {
int u=x,ff=fa[u];
LL ans=node[u][0].c1[1],a=0,b=0;
while (ff) {
int dist=getdist(x,ff);
if (dist<node[ff][0].size) {
node[ff][0].getsum(dist+1,a,b);
ans+=getfib(a,b,dist);
if (ans>=Mod) ans-=Mod;
node[ff][idx[u]].getsum(dist+1,a,b);
ans-=getfib(a,b,dist);
if (ans<0) ans+=Mod;
}
else cout<<"ERROR\n";
u=ff;
ff=fa[u];
}
return ans;
}
int main() {
freopen("fibtree.in","r",stdin);
freopen("fibtree.out","w",stdout);
n=read();q=read();
for (int i=1;i<n;i++) {
int x=read(),y=read();
addedge(x,y);
}
pow2[0]=1;
for (int i=1;i<=18;i++) pow2[i]=pow2[i-1]<<1;
dfs(1,1,0);
ST(n*2-1);
fib1[0]=1;fib2[1]=1;
for (int i=2;i<=n;i++) {
fib1[i]=fib1[i-1]+fib1[i-2];
if (fib1[i]>=Mod) fib1[i]-=Mod;
fib2[i]=fib2[i-1]+fib2[i-2];
if (fib2[i]>=Mod) fib2[i]-=Mod;
}
mxs[0]=(n<<1);root=0;
getroot(1,0,n);
solve(root,n);
for (int i=1;i<=q;i++) {
int op=read(),u=read();
if (op==1) {
int m=read(),a=read(),b=read();
modify(u,m,a,b);
}
else {
printf("%lld\n",query(u));
}
}
return 0;
}
只是對拍了一下,正確性不能保證,但應該沒問題。