hdu 3804(树链剖分+线段树)

题意:给出一棵树,Q个询问x,w,x到1的路径上不超过w的最长边是多少。

思路:题目读完了就知道用熟练剖分处理,然后可以用线段树求,线段树学的不是很好,就问了lyf怎么处理数据,他说把所有的询问按照权值的大小排序,边的大小也按权值排序,然后对每个询问把小于等于该权值的边加到树上就可以了。







#pragma comment(linker, "/STACK:10240000000000,10240000000000")
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
const int N=101000;
const int inf=0x3fffffff;
struct edge
{
	int st,ed,w,next;
}e[N*2];
struct node
{
	int x,id,w,mw;
}P[N],Q[N];
int cmp(void const *a,void const *b)
{
	node *c,*d;
	c=(node *)a;
	d=(node *)b;
	return c->w-d->w;
}
int amp(void const *a,void const *b)
{
	node *c,*d;
	c=(node *)a;
	d=(node *)b;
	return c->id-d->id;
}
int max(int a,int b)
{
	if(a>b)return a;
	return b;
}
int head[N],father[N],son[N],sz[N],dep[N],num,cot[N],idx,ti[N],top[N],ans;
void addedge(int x,int y,int w)
{
	e[num].st=x;e[num].ed=y;e[num].w=w;e[num].next=head[x];head[x]=num++;
	e[num].st=y;e[num].ed=x;e[num].w=w;e[num].next=head[y];head[y]=num++;
}
//***************树链剖分********************
void find_son(int u)
{
	int i,v;
	son[u]=0;sz[u]=1;
	for(i=head[u];i!=-1;i=e[i].next)
	{
		v=e[i].ed;
		if(v==father[u])continue;
		father[v]=u;
		dep[v]=dep[u]+1;
		cot[v]=e[i].w;
		find_son(v);
		sz[u]+=sz[v];
		if(sz[son[u]]<sz[v])son[u]=v;
	}
}
void find_time(int u,int fa)
{
	int i,v;
	top[u]=fa;
	ti[u]=idx++;
	P[ans].id=ti[u];//在线段树中的序号
	P[ans++].w=cot[u];//权值
	if(son[u]!=0)find_time(son[u],top[u]);
	for(i=head[u];i!=-1;i=e[i].next)
	{
		v=e[i].ed;
		if(v==son[u]||v==father[u])continue;
		find_time(v,v);
	}
}
//************线段树************************
struct Tree
{
	int L,R,mw;
}T[N*6];
void buildTree(int L,int R,int id)
{
	T[id].L=L;T[id].R=R;T[id].mw=-inf;
	if(L==R)return ;
	int mid=(L+R)>>1,li=id<<1,ri=li|1;
	buildTree(L,mid,li);
	buildTree(mid+1,R,ri);
}
void insertTree(int x,int w,int id)
{
	if(T[id].L==T[id].R)
	{
		T[id].mw=w;return ;
	}
	int mid=(T[id].L+T[id].R)>>1,li=id<<1,ri=li|1;
	if(x<=mid)insertTree(x,w,li);
	else insertTree(x,w,ri);
	T[id].mw=max(T[li].mw,T[ri].mw);
}
int find(int L,int R,int id)
{
	if(T[id].L==L&&T[id].R==R)
		return T[id].mw;
	int mid=(T[id].L+T[id].R)>>1,li=id<<1,ri=li|1;
	if(R<=mid)return find(L,R,li);
	else if(L>mid)return find(L,R,ri);
	else return max(find(L,mid,li),find(mid+1,R,ri));
}
int lca(int x,int y,int w)
{
	int Max=-1;
	while(dep[top[y]]>dep[top[x]])
	{
		Max=max(Max,find(ti[top[y]],ti[y],1));
		y=father[top[y]];
	}
	if(x!=y)
	  Max=max(Max,find(ti[x],ti[y],1));
	return Max;
}
int main()
{
	int i,n,m,x,y,w,j,t;
	scanf("%d",&t);
	while(t--)
	{
		memset(head,-1,sizeof(head));
		num=0;
		scanf("%d",&n);
		for(i=1;i<n;i++)
		{
			scanf("%d%d%d",&x,&y,&w);
			addedge(x,y,w);
		}
		father[1]=0;
		sz[0]=0;dep[1]=1;cot[1]=0;
		find_son(1);
		idx=1;ans=0;
		find_time(1,1);
		buildTree(1,n,1);
		qsort(P,n,sizeof(P[0]),cmp);
		scanf("%d",&m);
		for(i=0;i<m;i++)
		{
			scanf("%d%d",&Q[i].x,&Q[i].w);
			Q[i].id=i;
		}
		qsort(Q,m,sizeof(Q[0]),cmp);		
		for(i=0,j=1;i<m;i++)
		{
			while(P[j].w<=Q[i].w&&j<=n)//加边
			{
				insertTree(P[j].id,P[j].w,1);
				j++;
			}
			Q[i].mw=lca(1,Q[i].x,Q[i].w);//查找最大值
		}
		qsort(Q,m,sizeof(Q[0]),amp);
		for(i=0;i<m;i++)
		{
			printf("%d\n",Q[i].mw);
		}
	}
	return 0;
}

点赞