我好像只会套路数据结构题了…
暴力上点分树,这样的递推形式可以用矩阵表示,那么对于点
i
,它的线段树上区间覆盖上
然后询问点
i
管辖的点
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <ctime>
#include <assert.h>
using namespace std;
const int N=300010,P=1e9+7;
struct mat{
int a[2][2];
mat(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=0; }
int &val(){ return a[0][0]; }
friend mat operator *(mat a,mat b){
mat ret;
ret.a[0][0]=(1LL*a.a[0][0]*b.a[0][0]+1LL*a.a[0][1]*b.a[1][0])%P;
ret.a[0][1]=(1LL*a.a[0][0]*b.a[0][1]+1LL*a.a[0][1]*b.a[1][1])%P;
ret.a[1][0]=(1LL*a.a[1][0]*b.a[0][0]+1LL*a.a[1][1]*b.a[1][0])%P;
ret.a[1][1]=(1LL*a.a[1][0]*b.a[0][1]+1LL*a.a[1][1]*b.a[1][1])%P;
return ret;
}
friend mat operator +(mat a,mat b){
mat ret;
ret.a[0][0]=(a.a[0][0]+b.a[0][0])%P;
ret.a[0][1]=(a.a[0][1]+b.a[0][1])%P;
ret.a[1][0]=(a.a[1][0]+b.a[1][0])%P;
ret.a[1][1]=(a.a[1][1]+b.a[1][1])%P;
return ret;
}
friend mat operator -(mat a,mat b){
mat ret;
ret.a[0][0]=(a.a[0][0]-b.a[0][0])%P;
ret.a[0][1]=(a.a[0][1]-b.a[0][1])%P;
ret.a[1][0]=(a.a[1][0]-b.a[1][0])%P;
ret.a[1][1]=(a.a[1][1]-b.a[1][1])%P;
return ret;
}
};
inline int mul(mat a,mat b){
return (1LL*a.a[0][0]*b.a[0][0]+1LL*a.a[0][1]*b.a[1][0])%P;
}
mat f[N],u;
int t;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
int n,q,cnt,G[N];
struct edge{
int t,nx;
}E[N<<1];
inline void addedge(int x,int y){
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}
int fa[N][20],dpt[N];
inline int lca(int x,int y){
if(dpt[x]<dpt[y]) swap(x,y);
for(int i=19;~i;i--)
if(dpt[fa[x][i]]>=dpt[y]) x=fa[x][i];
if(x==y) return x;
for(int i=19;~i;i--)
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
inline int dist(int x,int y){
return dpt[x]+dpt[y]-2*dpt[lca(x,y)];
}
int deep[N];
namespace T{
int cnt,G[N],fa[N];
struct edge{
int t,nx;
}E[N<<1];
int ls[N*50],rs[N*50]; mat tag[N*50];
int t,root[N],droot[N];
int Dis[N][30];
inline void addedge(int x,int y){
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
fa[y]=x;
}
void clear(){
t=cnt=0;
for(int i=1;i<=n;i++) root[i]=droot[i]=G[i]=fa[i]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=20;j++) Dis[i][j]=0;
}
void Pre(){
for(int i=1;i<=n;i++)
for(int x=fa[i],j=1;x;x=fa[x],j++)
Dis[i][j]=dist(i,x);
}
void Add(int &g,int l,int r,int L,int R,mat c){
if(!g) g=++t,tag[g]=mat(),ls[g]=rs[g]=0;
if(l==L && r==R){
tag[g]=tag[g]+c; return ;
}
int mid=L+R>>1;
if(r<=mid) Add(ls[g],l,r,L,mid,c);
else if(l>mid) Add(rs[g],l,r,mid+1,R,c);
else Add(ls[g],l,mid,L,mid,c),Add(rs[g],mid+1,r,mid+1,R,c);
}
mat Query(int g,int x,int L,int R){
mat ret;
while(g){
ret=ret+tag[g];
if(L==R) break;
int mid=L+R>>1;
if(x<=mid) g=ls[g],R=mid; else g=rs[g],L=mid+1;
}
return ret;
/*if(!g) return mat();
if(L==R) return tag[g];
int mid=L+R>>1;
if(x<=mid) return Query(ls[g],x,L,mid)+tag[g];
else return Query(rs[g],x,mid+1,R)+tag[g];*/
}
inline void Add(int x,int k,mat c){
Add(root[x],0,min(k,deep[x]),0,deep[x],c);
for(int i=x,j=1;fa[i];i=fa[i],j++){
int dis=Dis[x][j];
if(dis>k) continue;
Add(droot[i],0,min(k-dis,deep[fa[i]]),0,deep[fa[i]],c*f[dis]);
Add(root[fa[i]],0,min(k-dis,deep[fa[i]]),0,deep[fa[i]],c*f[dis]);
}
}
inline int Query(int x){
int ret=Query(root[x],0,0,deep[x]).val();
for(int i=x,j=1;fa[i];i=fa[i],j++){
int dis=Dis[x][j];
assert(dis<=deep[fa[i]]);
ret=(ret+mul((Query(root[fa[i]],dis,0,deep[fa[i]])-Query(droot[i],dis,0,deep[fa[i]])),f[dis]))%P;
}
return (ret+P)%P;
}
void dfs(int x){
deep[x]=1;
for(int i=G[x];i;i=E[i].nx)
dfs(E[i].t),deep[x]=max(deep[x],deep[E[i].t]+1);
}
}
int root,imax,size,vis[N];
void Size(int x,int f){
size++; for(int i=G[x];i;i=E[i].nx)if(E[i].t!=f && !vis[E[i].t]) Size(E[i].t,x);
}
int Root(int x,int f){
int ret=1,cmax=0;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f && !vis[E[i].t]){
int cur=Root(E[i].t,x);
cmax=max(cmax,cur);
ret+=cur;
}
cmax=max(cmax,size-ret);
if(cmax<imax) imax=cmax,root=x;
return ret;
}
int Deep(int x,int f){
int ret=0;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f && !vis[E[i].t]) ret=max(Deep(E[i].t,x),ret);
return ret+1;
}
void build(int x,int f){
size=0; Size(x,0);
imax=1<<30; Root(x,0); deep[root]=Deep(root,0);
if(f) T::addedge(f,root);
vis[root]=1; int croot=root;
for(int i=G[root];i;i=E[i].nx)
if(!vis[E[i].t]) build(E[i].t,croot);
}
void dfs(int x,int f){
dpt[x]=dpt[f]+1;
fa[x][0]=f; for(int i=1;i<=19;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f) dfs(E[i].t,x);
}
void PutAns(int x){
if(x>=10) PutAns(x/10); putchar(x%10+'0');
}
int main(){
u.a[0][0]=u.a[0][1]=u.a[1][0]=1;
f[0].a[0][0]=f[0].a[1][1]=1;
for(int i=1;i<=300000;i++) f[i]=f[i-1]*u;
read(t);
while(t--){
read(n); read(q); cnt=0;
for(int i=1;i<=n;i++) G[i]=vis[i]=0;
T::clear();
for(int i=1,x,y;i<n;i++)
read(x),read(y),addedge(x,y);
build(1,0); dfs(1,0); T::Pre();
while(q--){
int opt,v,k,a,b;
read(opt); read(v);
if(opt==1){
read(k); read(a); read(b);
mat c; c.a[0][0]=a; c.a[1][0]=c.a[0][1]=b-a;
T::Add(v,k,c);
}
else
PutAns(T::Query(v)),putchar('\n');
//printf("%d\n",T::Query(v));
}
}
return 0;
}