zoukankan      html  css  js  c++  java
  • 题解 USACO12DEC【逃跑的BarnRunning Away From…】

    期末考前写题解,(rp++! rp++! rp++!)

    [description ]

    给出一个(1) 为根的边带权有根树,给定一个参数 (L) ,问每个点的子树中与它距离小于等于 (L) 的节点个数。

    [solution ]

    有关子树内的统计,肯定能联想到 线段树合并 吧。

    (d[u]) 表示根节点到 (u) 的距离,该数组可通过一次遍历求出。

    则对于每个点 (u) ,它的贡献就是满足下式的点对数量:

    [d[v]-d[u]leq L { vinoperatorname{subtree}(u) } ]

    移项,可化简为:

    [d[v]leq d[u]+L { vinoperatorname{subtree}(u) } ]

    那么问题就转化成了:

    令点 (u) 的点权为 (d[u])。对于每个点 (u) ,求出该点的子树中点权小于等于 (d[u]+L) 的节点个数

    然后发现是一道 线段树合并 板子题,直接码上就行。

    需注意的是,这个 (L)(d[~]) 的范围有 (1e18) ,所以我们需要离散化一下防止 (MLE)

    我是把每个 (d[u]) 以及 (d[u]+L) 都扔进去离散化了,如果有哪位 (dalao) 有更优秀的离散化方法,可以评论在博客下方,我会感激不尽。

    [code ]

    #include<cstdio>
    #include<algorithm>
    
    #define RI register int
    
    using namespace std;
    
    const int N=200100,M=200100,MLOGN=10001000;
    
    int n,m;
    long long L;
    
    int Etot,head[N],ver[M],Next[M];
    long long edge[M];
    
    void add(int u,int v,long long w)
    {
    	ver[++Etot]=v;    edge[Etot]=w;    Next[Etot]=head[u];    head[u]=Etot;
    }
    
    long long d[N];
    
    int len;
    long long mapval[1000100];
    
    void discrete()
    {
    	sort(mapval+1,mapval+1+len);
    	len=unique(mapval+1,mapval+1+len)-mapval-1;
    }
    
    int query(long long x)
    {
    	return lower_bound(mapval+1,mapval+1+len,x)-mapval;
    }
    
    int tot,root[N];
    struct SegmentTree{
    	int lc,rc;
    	int cnt;
    }t[MLOGN];
    
    int New()
    {
    	tot++;
    	t[tot].lc=t[tot].rc=t[tot].cnt=0;
    	return tot;
    }
    
    void insert(int &p,int l,int r,int delta,int val)
    {
    	if(!p)p=New();
    	t[p].cnt+=val;
    	if(l==r)return;
    	int mid=(l+r)/2;
    	if(delta<=mid)
    		insert(t[p].lc,l,mid,delta,val);
    	else
    		insert(t[p].rc,mid+1,r,delta,val);
    }
    
    int merge(int p,int q)
    {
    	if(!p||!q)return p^q;
    	t[p].cnt+=t[q].cnt;
    	t[p].lc=merge(t[p].lc,t[q].lc);
    	t[p].rc=merge(t[p].rc,t[q].rc);
    	return p;
    }
    
    int ask(int p,int l,int r,int s,int e)
    {
    	if(!p)return 0;
    	if(s<=l&&r<=e)return t[p].cnt;
    	int mid=(l+r)/2;
    	int val=0;
    	if(s<=mid)
    		val+=ask(t[p].lc,l,mid,s,e);
    	if(mid<e)
    		val+=ask(t[p].rc,mid+1,r,s,e);
    	return val;
    }
    
    void dfs1(int u)
    {
    	mapval[++len]=d[u],mapval[++len]=d[u]+L;
    	for(RI i=head[u];i;i=Next[i])
    	{
    		int v=ver[i];
    		long long w=edge[i];
    		d[v]=d[u]+w;
    		dfs1(v);
    	}
    }
    
    int ans[N];
    
    void dfs2(int u)
    {
    	for(RI i=head[u];i;i=Next[i])
    	{
    		int v=ver[i];
    		dfs2(v);
    		root[u]=merge(root[u],root[v]);
    	}
    	insert(root[u],1,len,query(d[u]),1);
    	ans[u]=ask(root[u],1,len,1,query(d[u]+L));
    }
    
    int main()
    {
    	scanf("%d%lld",&n,&L);
    
    	for(RI i=2;i<=n;i++)
    	{
    		int fa;
    		long long w;
    		scanf("%d%lld",&fa,&w);
    		add(fa,i,w);
    	}
    
    	dfs1(1);
    
    	discrete();
    
    	dfs2(1);
    
    	for(RI i=1;i<=n;i++)
    		printf("%d
    ",ans[i]);
    
    	return 0;
    }
    

    [thanks for watching ]

  • 相关阅读:
    Cordova 混合开发
    可能比文档还详细--VueRouter完全指北
    VUE项目实现页面跳转
    Vuex结合 async/await 优雅的管理接口请求
    vuex深入理解 modules
    vuex学习与实践——mapState、getter、mapGetters
    vuex里mapState,mapGetters使用详解
    vue.js相关UI组件收集
    vuex最简单、最直白、最全的入门文档
    深入理解表单脚本系列第三篇——选择文本
  • 原文地址:https://www.cnblogs.com/cjtcalc/p/12216676.html
Copyright © 2011-2022 走看看