bzoj-3011 Running Away From the Barn

题意:

给出以1号点为根的一棵有根树,问每个点的子树中与它距离小于等于L的点有多少个。

n<=200000;

题解:

这题比较有意思;

首先考虑的就是树形DP,但是DP完全无法转移;

考虑一个结点的答案,那就是子树中与这个结点距离小于等于L的点数(废话);

那它父亲在这个子树的答案呢?

子树中每个点的距离都增加了,而相对大小关系没有改变;

所以就用一个可并堆来维护子树,每次将堆中距离过大的点pop掉;

堆中长度直接用这个点到1的长度,而到当前子树根的距离在减去子树根到1的长度就是了;

然后统计堆的大小,再将堆向上合并;

时间复杂度是O(nlogn),扫一遍树就出解了;

如果边权带负怎么办?

每个点可能加入堆中多次,但是如果搞一个对顶堆复杂度就不对了;

所以上启发式合并平衡树= =,O(nlog^2n)解决了;

代码:

#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 210000
using namespace std;
typedef long long ll;
int ch[N][2],dis[N],size[N];
int out[N],fa[N],root[N],ans[N];
ll L[N];
queue<int>q;
void Pushup(int x)
{
	size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
int merge(int x,int y)
{
	if(!x||!y)	return x+y;
	if(L[x]<L[y])
		swap(x,y);
	ch[x][1]=merge(ch[x][1],y);
	Pushup(x);
	if(dis[ch[x][0]]<dis[ch[x][1]])
		swap(ch[x][0],ch[x][1]);
	dis[x]=dis[ch[x][1]]+1;
	return x;
}
int main()
{
	int n,i,j,k,x,y;
	ll m;
	scanf("%d%lld",&n,&m);
	dis[0]=-1,size[1]=1,root[1]=1;
	for(i=2;i<=n;i++)
	{
		scanf("%d%lld",fa+i,L+i);
		out[fa[i]]++,size[i]=1,root[i]=i;
		L[i]+=L[fa[i]];
	}
	for(i=1;i<=n;i++)
	{
		if(out[i]==0)
			q.push(i);
	}
	out[0]++;
	while(!q.empty())
	{
		x=q.front(),q.pop();
		while(L[root[x]]-L[x]>m)
			root[x]=merge(ch[root[x]][0],ch[root[x]][1]);
		ans[x]=size[root[x]];
		y=fa[x];
		root[y]=merge(root[y],root[x]);
		out[y]--;
		if(!out[y])
			q.push(y);
	}
	for(i=1;i<=n;i++)
		printf("%d\n",ans[i]);
	return 0;
}
时间: 2024-12-22 12:15:15

bzoj-3011 Running Away From the Barn的相关文章

BZOJ 3011: [Usaco2012 Dec]Running Away From the Barn( dfs序 + 主席树 )

子树操作, dfs序即可.然后计算<=L就直接在可持久化线段树上查询 ------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; #define M(l, r) (((l) + (r)) >> 1) const int maxn = 200009; typedef long long ll; inline ll

【BZOJ3011】[Usaco2012 Dec]Running Away From the Barn 可并堆

[BZOJ3011][Usaco2012 Dec]Running Away From the Barn Description It's milking time at Farmer John's farm, but the cows have all run away! Farmer John needs to round them all up, and needs your help in the search. FJ's farm is a series of N (1 <= N <=

bzoj3011[Usaco2012 Dec]Running Away From the Barn*

bzoj3011[Usaco2012 Dec]Running Away From the Barn 题意: 给出以1号点为根的一棵有边权的树,问每个点的子树中与它距离小于l的点有多少个.树的大小≤200000. 题解: 每个节点维护一个带标记可并堆,dfs时对子节点的堆加上当前节点到该子节点的边权,之后令其与当前节点的堆合并. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #i

BZOJ 3011 Usaco2012 Dec Running Away From the Barn 可并堆

题目大意:给定一棵有根树,求以每个点为根的子树中有多少点到它的距离不超过l 第一眼是可并堆- - 于是怒写- - 管它正解是啥- - 从下到上维护可并大根堆 键值是该点到当前根节点的距离 一旦堆顶剪枝大于l就弹顶 时间复杂度O(nlogn) 什么?你说将整个堆都加上一个值? 打标记不就好了- - 毫无疑问可并堆是可以打标记的- - 此外我的随机堆写if(flag^=1)就T写if(rand()&1)就秒过是什么鬼- - #include <cstdio> #include <cs

bzoj 3011

传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=3011 一想到这个第一反应是树形dp,然后10^18 (' '    ) 所以我直接搞了一个左偏树往上面不断合并(' '     ) 网上好像有人用的线段树维护区间(子树)最小值,不过我觉得我这个做法比较好写吧. #include <iostream> #include <cstdio> #include <cstring> #include <algori

[USACO 12DEC]Running Away From the Barn

Description It's milking time at Farmer John's farm, but the cows have all run away! Farmer John needs to round them all up, and needs your help in the search. FJ's farm is a series of N (1 <= N <= 200,000) pastures numbered 1...N connected by N - 1

Bzoj 1696: [Usaco2007 Feb]Building A New Barn新牛舍 中位数,数学

1696: [Usaco2007 Feb]Building A New Barn新牛舍 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 394  Solved: 181[Submit][Status][Discuss] Description 经过多年的积蓄,农夫JOHN决定造一个新的牛舍.他知道所有N(2 <= N <= 10,000)头牛的吃草位置,所以他想把牛舍造在最方便的地方. 每一头牛吃草的位置是一个整数点(X_i, Y_i) (-10,0

BZOJ 1613: [Usaco2007 Jan]Running贝茜的晨练计划( dp)

dp乱搞即可...( 我就是这样 A 的.. 后来想改快一点..然后就WA了...不理了 ------------------------------------------------------------------------------------------ #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n )

bzoj 4412: [Usaco2016 Feb]Circular Barn

4412: [Usaco2016 Feb]Circular Barn Description 有一个N个点的环,相邻两个点距离是1.点顺时针标号为1..N.每一个点有ci头牛,保证∑ci=N.每头牛都可以顺时针走.设一头牛走了d个单位停下了,将耗费d^2的能量.请设计一种牛的走法,使得每一个点上都正好有一头牛,且最小化耗费的能量. Input 第一行一个数N.N <= 100000接下来N行,每行一个数ci. Output 输出一个数表示耗费能量的最小值 Sample Input 10 1 0