【BZOJ3307】雨天的尾巴 线段树合并

【BZOJ3307】雨天的尾巴

Description

N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。

Input

第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题

Output

输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有多种物品的数量一样,输出编号最小的。如果某个点没有物品则输出0

题解:看到题直接的想法就是树套树,但是由于可以离线,我们可以直接差分。

具体地,我们对于每个点都维护一棵权值线段树,然后将标记差分,最后将每个节点的线段树与父亲节点的线段树合并即可。

建议:在一开始的时候就为每个点创建一个rt节点。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100010;
int inf=1000000000;
int n,m,cnt,tot;
int to[maxn<<1],next[maxn<<1],head[maxn],fa[19][maxn],dep[maxn],rt[maxn],p[maxn],ref[maxn];
int v[maxn*50],s[maxn*50],ls[maxn*50],rs[maxn*50];
struct node
{
	int a,b,c;
}q[maxn];
bool cmp(node a,node b)
{
	return a.c<b.c;
}
int rd()
{
	int ret=0;	char gc=getchar();
	while(gc<'0'||gc>'9')	gc=getchar();
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret;
}
void add(int a,int b)
{
	to[++cnt]=b,next[cnt]=head[a],head[a]=cnt;
}
void dfs(int x)
{
	p[++p[0]]=x;
	for(int i=head[x];i;i=next[i])
		if(to[i]!=fa[0][x])	fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
}
int lca(int a,int b)
{
	if(dep[a]<dep[b])	swap(a,b);
	for(int i=18;i>=0;i--)	if(dep[fa[i][a]]>=dep[b])	a=fa[i][a];
	if(a==b)	return a;
	for(int i=18;i>=0;i--)	if(fa[i][a]!=fa[i][b])	a=fa[i][a],b=fa[i][b];
	return fa[0][a];
}
void pushup(int x)
{
	v[x]=max(v[ls[x]],v[rs[x]]);
	s[x]=(v[ls[x]]>=v[rs[x]])?s[ls[x]]:s[rs[x]];
}
void insert(int &x,int a,int b,int l,int r)
{
	if(!x)	x=++tot;
	if(l==r)
	{
		v[x]+=b,s[x]=ref[l];
		return ;
	}
	int mid=l+r>>1;
	if(a<=mid)	insert(ls[x],a,b,l,mid);
	else	insert(rs[x],a,b,mid+1,r);
	pushup(x);
}
void merge(int &a,int b,int l,int r)
{
	if(!b)	return ;
	if(!a)
	{
		a=b;
		return ;
	}
	if(l==r)
	{
		v[a]+=v[b];
		return ;
	}
	int mid=l+r>>1;
	merge(ls[a],ls[b],l,mid),merge(rs[a],rs[b],mid+1,r);
	pushup(a);
}
int main()
{
	int i,j,a,b,c,d;
	n=rd(),m=rd();
	for(i=1;i<=n;i++)	rt[i]=++tot;
	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
	dep[1]=1,dfs(1);
	for(j=1;(1<<j)<=n;j++)	for(i=1;i<=n;i++)	fa[j][i]=fa[j-1][fa[j-1][i]];
	for(i=1;i<=m;i++)	q[i].a=rd(),q[i].b=rd(),q[i].c=rd();
	sort(q+1,q+m+1,cmp);
	for(d=0,i=1;i<=m;i++)
	{
		a=q[i].a,b=q[i].b,c=lca(a,b);
		if(q[i].c>q[i-1].c)	ref[++d]=q[i].c;
		insert(rt[a],d,1,0,m),insert(rt[b],d,1,0,m),insert(rt[c],d,-1,0,m);
		if(c!=1)	insert(rt[fa[0][c]],d,-1,0,m);
	}
	for(i=n;i>1;i--)	merge(rt[fa[0][p[i]]],rt[p[i]],0,m);
	for(i=1;i<=n;i++)	printf("%d\n",s[rt[i]]);
	return 0;
}
posted @ 2017-08-03 09:27  CQzhangyu  阅读(807)  评论(2编辑  收藏  举报