newcoder Wannafly挑战赛4 树的距离
https://www.nowcoder.com/acm/contest/35/D
假设要查询x的子树中,与x的距离>=y的距离和
那么如果有这么一个
由x的子树中的点到x的距离构成的序列,且按距离排好序,
那么在这个序列中,y之后的距离和就是答案
得到子树中按距离排好序的一段序列
按dfs序建立主席树即可
每次查询抽出x的子树序列,
注意主席树的权值是按点到根节点的距离
所以 查询dis[x]+y之后的距离和,再减去 x子树大小*dis[x]
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 200001 typedef long long LL; int n; int front[N],nxt[N<<1],to[N<<1],val[N<<1]; int tot,TOT; int in[N],out[N],id[N]; LL has[N],dep[N]; int root[N],lc[N*20],rc[N*20],cnt[N*20]; LL sum[N*20]; LL ans; int num; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void add(int u,int v,int w) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w; } void predfs(int x,int y) { in[x]=++tot; id[tot]=x; for(int i=front[x];i;i=nxt[i]) if(to[i]!=y) dep[to[i]]=has[to[i]]=dep[x]+val[i],predfs(to[i],x); out[x]=tot; } void insert(int &x,int y,int l,int r,int pos) { x=++tot; sum[x]=sum[y]+has[pos]; cnt[x]=cnt[y]+1; if(l==r) return; int mid=l+r>>1; if(pos<=mid) rc[x]=rc[y],insert(lc[x],lc[y],l,mid,pos); else lc[x]=lc[y],insert(rc[x],rc[y],mid+1,r,pos); } void build() { sort(has+1,has+n+1); TOT=unique(has+1,has+n+1)-has-1; tot=0; for(int i=1;i<=n;++i) insert(root[i],root[i-1],1,TOT,lower_bound(has+1,has+TOT+1,dep[id[i]])-has); } void query(int x,int y,int l,int r,int pos) { if(l==r) { ans+=sum[x]-sum[y]; num+=cnt[x]-cnt[y]; return; } int mid=l+r>>1; if(pos<=mid) { ans+=sum[rc[x]]-sum[rc[y]]; num+=cnt[rc[x]]-cnt[rc[y]]; query(lc[x],lc[y],l,mid,pos); } else query(rc[x],rc[y],mid+1,r,pos); } int main() { freopen("data.in","r",stdin); freopen("my.out","w",stdout); int x,y; read(n); for(int i=1;i<n;++i) { read(x); read(y); add(i+1,x,y); } tot=0; predfs(1,0); build(); int m,pos; read(m); while(m--) { read(x); read(y); pos=lower_bound(has+1,has+TOT+1,dep[x]+y)-has; if(pos>TOT) puts("0"); else { ans=0; num=0; query(root[out[x]],root[in[x]-1],1,TOT,pos); cout<<ans-num*dep[x]<<'\n'; } } }
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
wyf非常喜欢树。一棵有根数树上有N个节点,1号点是他的根,每条边都有一个距离,而wyf是个爱问奇怪问题的熊孩子,他想知道对于某个点x,以x为根的子树上,所有与x距离大于等于k的点与x的距离之和。
输入描述:
第一行一个正整数N
接下来N-1描述这棵树,每行两个数第i行两个数p和D表示树上有一条p到i+1长度为D的边。(p<=i)
下面一行一个正整数Q表示wyf的询问次数。
接下来Q行每行两个正整数x和k。 (1<=N,Q<=2x105,1<=D,K<=106)
输出描述:
对于每次询问x,k输出以x为根的子树上,所有与x距离大于等于k的点与x的距离之和。(若不存在这样的点,则输出应为0)
示例1
输入
3 1 2 1 3 2 1 3 1 2
输出
3 5