题意:给出一棵树,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; }