zoukankan      html  css  js  c++  java
  • Codechef March Challenge 2021 Random Walk Queries(RWALKS) (动态点分治)

    Codechef March Challenge 2021 Random Walk Queries(RWALKS) (动态点分治)

    题目大意:

    对于给定的无根树(T),要求强制在线维护两种操作

    1.游走((u,d)),以(u)为根在树上游走,从(u)开始,最多走(d)步,每次随机从儿子中选择一个点

    2.查询(u),当前(u)被遍历的期望次数

    [ ]

    灵光一闪想到这么个憨批树上结构

    对于更新((u,d)),考虑(u) 跨过当前点分根 到达其他点分子树里的贡献

    一个点由当前点分根到达的概率是一个定值,可以预处理出来,并在查询时计算

    因此更新贡献时,可以描述为(depleq d)的点接受到 以(x)的概率访问当前点分根

    可以简单用树状数组维护

    为了剔除对于自己所在子树的非法贡献,需要额外开一些树状数组来维护

    一个节点有(log n)个点分父节点,每次需要两次树状数组查询

    因此查询部分复杂度为(O(mlog ^2n)),预处理以及空间复杂度为(O(nlog 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
    ",lst=Que(Get()));
    	}
    }
    
  • 相关阅读:
    CentOS安装使用.netcore极简教程(免费提供学习服务器)
    新生命团队netcore服务器免费开放计划
    线程池ThreadPool及Task调度死锁分析
    NetCore版RPC框架NewLife.ApiServer
    NewLife.Net——管道处理器解决粘包
    NewLife.Net——网络压测单机2266万tps
    NewLife.Net——构建可靠的网络服务
    NewLife.Net——开始网络编程
    搬家
    借助Redis做秒杀和限流的思考
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14548817.html
Copyright © 2011-2022 走看看