zoukankan      html  css  js  c++  java
  • 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]<<'
    ';
            }
        }
    }
    时间限制:C/C++ 2秒,其他语言4秒
    空间限制: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
  • 相关阅读:
    String和inputstream互转【转文】
    shell学习笔记
    如何实现网页标题的闪动提示
    JAVAWEB项目如何实现验证码
    Oralce数据库的优化(面试必问题)
    sqlldr 学习总结1
    各种浏览器的Hack写法(chrome firefox ie等)
    存储过程
    App Store那些事儿
    JBMP学习引导
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7894393.html
Copyright © 2011-2022 走看看