zoukankan      html  css  js  c++  java
  • CF494D Birthday

    CF494D Birthday

    题意

    一个1为根的带边权有根树,每次询问给定两个点 (u,v)(sum_{xin S(v)} d(u,x)^2-sum_{x otin S(v)}d(u,x)^2) 其中 (d(u,v)) 表示 (u,v) 简单路径长度, (S(u)) 表示 (u) 的子树内点的集合。

    思路

    考虑 (u)(v) 内和在 (v) 外的情况,发现可以通过每个点维护四个值——子树内所有点到其距离的和、子树内所有点到其距离的平方的和、所有点到其的距离和、所有点到其距离的平方和——来回答询问。

    具体转移细节请自推,这里总结一个重点:

    (v)(u) 两点,(f2[v])(v) 子树内距离平方的和,(f[v])(v) 子树内距离的和,(siz[v])(v) 子树大小,(w) 为两点间距离,则 (v) 子树内所有点到 (u) 的距离的平方和为

    [f2[v]+2*f[v]*w+siz[v]*w^2 ]

    深度优先搜索两边换根处理出以上信息后分类讨论即可。

    代码

    请注意取模。

    代码中的一些取模可以被优化。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #include<cmath>
    #define int long long
    using namespace std;
    inline int read(){
    	int w=0,x=0;char c=getchar();
    	while(!isdigit(c))w|=c=='-',c=getchar();
    	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	return w?-x:x;
    }
    namespace star
    {
    	const int maxn=1e5+10,mod=1e9+7;
    	int n;
    	int ecnt,head[maxn],to[maxn<<1],nxt[maxn<<1],v[maxn<<1];
    	inline void addedge(int a,int b,int c){
    		to[++ecnt]=b,nxt[ecnt]=head[a],head[a]=ecnt,v[ecnt]=c;
    		to[++ecnt]=a,nxt[ecnt]=head[b],head[b]=ecnt,v[ecnt]=c;
    	}
    	inline int up(int a){return a>=mod?a-mod:a;}
    	inline int dn(int a){return a<0?a+mod:a;}
    	int f[maxn],f2[maxn],g[maxn],g2[maxn],dep[maxn],fa[maxn][21],dis[maxn],siz[maxn];
    	void dfs(int x,int father){
    		fa[x][0]=father;siz[x]=1;
    		dep[x]=dep[father]+1;
    		for(int i=0;i<20;i++) fa[x][i+1]=fa[fa[x][i]][i];
    		for(int i=head[x];i;i=nxt[i]){
    			int u=to[i];
    			if(u==father)continue;
    			dis[u]=dis[x]+v[i];
    			dfs(u,x);
    			siz[x]+=siz[u];
    			f[x]=up(f[x]+up(f[u]+siz[u]*v[i]%mod))%mod;
    			f2[x]=((f2[x]+f2[u])%mod+(siz[u]*v[i]%mod*v[i]%mod+2*v[i]*f[u]%mod)%mod)%mod;
    		}
    	}
    	void dfs2(int x){
    		for(int i=head[x];i;i=nxt[i]){
    			int u=to[i];
    			if(u==fa[x][0])continue;
    			g[u]=(g[x]+(n-2*siz[u]+mod)%mod*v[i]%mod)%mod;
    			g2[u]=((f2[u]+(g2[x]-((f2[u]+2*v[i]%mod*f[u]%mod)%mod+siz[u]*v[i]%mod*v[i]%mod)%mod+mod)%mod)%mod+((g[x]-f[u]+mod-siz[u]*v[i]%mod+mod)%mod*2%mod*v[i]%mod+(n-siz[u])*v[i]%mod*v[i]%mod)%mod)%mod;
    			dfs2(u);
    		}
    	}
    	inline int LCA(int x,int y){
    		if(dep[x]<dep[y])swap(x,y);
    		for(int i=20;~i;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    		if(x==y) return x;
    		for(int i=20;~i;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    		return fa[x][0];
    	}
    	inline void work(){
    		n=read();
    		for(int u,v,i=1;i<n;i++) u=read(),v=read(),addedge(u,v,read());
    		dfs(1,0);
    		g[1]=f[1],g2[1]=f2[1];
    		dfs2(1);
    		int Q=read();
    		while(Q--){
    			int y=read(),x=read(),lca=LCA(x,y),d=dis[x]+dis[y]-dis[lca]*2;
    			d%=mod;
    			if(lca==x){
    				printf("%lld
    ",(g2[y]-2*((((g2[x]-f2[x]+mod)%mod+2*d%mod*(g[x]-f[x]+mod)%mod)%mod+d*d%mod*(n-siz[x])%mod)%mod+mod)%mod+mod)%mod);
    			}else{
    				printf("%lld
    ",((((f2[x]%mod+2%mod*d%mod*f[x]%mod)%mod+d%mod*d%mod*siz[x]%mod)%mod*2%mod-g2[y]%mod)%mod+mod)%mod);
    			}
    		}
    	}
    }
    signed main(){
    	star::work();
    	return 0;
    }
    
  • 相关阅读:
    Codeforces 1265A Beautiful String
    1039 Course List for Student (25)
    1038 Recover the Smallest Number (30)
    1037 Magic Coupon (25)
    1024 Palindromic Number (25)
    1051 Pop Sequence (25)
    1019 General Palindromic Number (20)
    1031 Hello World for U (20)
    1012 The Best Rank (25)
    1011 World Cup Betting (20)
  • 原文地址:https://www.cnblogs.com/BrotherHood/p/13889616.html
Copyright © 2011-2022 走看看