Codechef March Challenge 2021 Random Walk Queries(RWALKS) (动态点分治)
题目大意:
对于给定的无根树\(T\),要求强制在线维护两种操作
1.游走\((u,d)\),以\(u\)为根在树上游走,从\(u\)开始,最多走\(d\)步,每次随机从儿子中选择一个点
2.查询\(u\),当前\(u\)被遍历的期望次数
\[\ \]灵光一闪想到这么个憨批树上结构
对于更新\((u,d)\),考虑\(u\) 跨过当前点分根 到达其他点分子树里的贡献
一个点由当前点分根到达的概率是一个定值,可以预处理出来,并在查询时计算
因此更新贡献时,可以描述为\(dep\leq d\)的点接受到 以\(x\)的概率访问当前点分根
可以简单用树状数组维护
为了剔除对于自己所在子树的非法贡献,需要额外开一些树状数组来维护
一个节点有\(\log n\)个点分父节点,每次需要两次树状数组查询
因此查询部分复杂度为\(O(m\log ^2n)\),预处理以及空间复杂度为\(O(n\log n)\)
const int N=2e5+10,K=19,P=1e9+7;
int n,m,I[N];
struct Edge{
int to,nxt;
}e[N<<1];
int head[N],ecnt,deg[N];
void AddEdge(int u,int v){
e[++ecnt]=(Edge){v,head[u]};
head[u]=ecnt,deg[v]++;
}
#define erep(u) for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to)
struct BIT{
int n;
vector <int> s;
BIT(){};
BIT(int n):n(n){ s.resize(n+1); }
void Add(int p,int x){
for(cmin(p,n);p;p-=p&-p) s[p]+=x,Mod1(s[p]);
}
int Que(int p){
int res=0;
while(p<=n) res+=s[p],Mod1(res),p+=p&-p;
return res;
}
} T[N];
vector <BIT> G[N];
// Dep:点分树上的dep,id:节点在每层的编号, dep:节点在每层的dep,s:节点在每层由根到达的系数
int Dep[N],id[K][N],dep[K][N],s[K][N],vis[N],sz[N],fa[N],Root;
int mi,rt;
void FindRt(int n,int u,int f){
int ma=0; sz[u]=1;
erep(u) if(v!=f && !vis[v]) {
FindRt(n,v,u);
sz[u]+=sz[v],cmax(ma,sz[v]);
}
cmax(ma,n-sz[u]);
if(mi>ma) mi=ma,rt=u;
}
int D,maxd;
void dfs(int u,int f,int id){
cmax(maxd,dep[D][u]=dep[D][f]+1),::id[D][u]=id;
erep(u) if(v!=f && !vis[v]) {
s[D][v]=1ll*s[D][u]*I[deg[u]-1]%P;
dfs(v,u,id);
}
}
// 预处理点分治,开树状数组
int Divide(int n,int u){
mi=1e9,FindRt(n,u,0),u=rt;
int sonc=0;
vis[u]=s[Dep[u]=D][u]=1,id[D][u]=-1;
int t=0;
erep(u) if(!vis[v]) {
maxd=0;
s[D][v]=1,dfs(v,u,sonc);
G[u].pb(BIT(maxd));
sonc++;
cmax(t,maxd);
}
T[u]=BIT(t);
erep(u) if(!vis[v]) {
if(sz[v]>sz[u]) sz[v]=n-sz[u];
D++,fa[Divide(sz[v],v)]=u,D--;
}
return u;
}
int sum[N];
int Que(int u){
ll ans=sum[u];
for(int v=u,d=Dep[v];(d--,v=fa[v]);)
ans=(ans+ 1ll* (T[v].Que(dep[d][u])+G[v][id[d][u]].Que(dep[d][u])) *s[d][u])%P;
return (ans%P+P)%P;
}
void Upd(int u,int d){
sum[u]++,Mod1(sum[u]),T[u].Add(d,I[deg[u]]);
for(int v=fa[u],D=Dep[u]-1;v;v=fa[v],D--) {
if(d<dep[D][u]) continue;
int x=1ll*I[deg[u]]*s[D][u]%P;
sum[v]+=x,Mod1(sum[v]);
x=1ll*x*I[deg[v]-1]%P;
T[v].Add(d-dep[D][u],x),G[v][id[D][u]].Add(d-dep[D][u],P-x);
}
}
int lst;
int Get() { return (rd()+lst)%n+1; }
int main(){
I[0]=I[1]=1;
rep(i,2,N-1) I[i]=1ll*(P-P/i)*I[P%i]%P;
n=rd(),m=rd();
rep(i,2,n){
int u=rd(),v=rd();
AddEdge(u,v),AddEdge(v,u);
}
Root=Divide(n,1);
while(m--) {
int opt=rd();
if(opt==1) {
int u=Get(),d=Get();
Upd(u,d);
} else printf("%d\n",lst=Que(Get()));
}
}