题目:http://acm.hdu.edu.cn/showproblem.php?pid=3804
题意:给你一个树,每条边都有一个权值,现在有m组询问,每次询问输入一个二元组(x,y),其结果要满足以下两个条件的最大值
1、必须是从x->1路径上的一条边
2该边的权值必须<=y,且是最大的边
分析:把询问离线处理,先把原本树的边按权值从小到大排序,询问按y值从小到大排,对于边的权值可看作点的权值,每条边的权值都作为儿子结点的权值,根结点的权值赋为-1。
按照询问每次把<=y的边插入线段树,线段树维护区间最大值,再询问最大值,当然在树上维护线段树要树链剖分。
Ac code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int head[maxn],tot,n;
struct E{
int u,v,w;
};
vector<E>e;
struct Edge
{
int v,w,nxt;
} edge[maxn<<1];
int tree[maxn<<2];
int sze[maxn],fa[maxn],son[maxn],dfn[maxn],dep[maxn],rk[maxn],cnt,top[maxn];
void init()
{
e.clear();
memset(edge,0,sizeof edge);
tot=cnt=0;
memset(sze,0,sizeof sze);
memset(fa,0,sizeof fa);
memset(son,0,sizeof son);
memset(dfn,0,sizeof dfn);
memset(dep,0,sizeof dep);
dep[1]=1;
memset(rk,0,sizeof rk);
memset(head,-1,sizeof head);
}
struct Node
{
int x,y,id,ans;
} node[maxn];
bool cmp1(const Node& a,const Node& b)
{
return a.y<b.y;
}
bool cmp2(const Node& a,const Node& b)
{
return a.id<b.id;
}
void addedge(int u,int v,int w)
{
edge[tot].v=v;
edge[tot].w=w;
edge[tot].nxt=head[u];
head[u]=tot++;
}
void pushup(int rt)
{
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void buildtree(int rt,int l,int r)
{
if(l==r)
{
tree[rt]=-1;
return;
}
int mid=(l+r)>>1;
buildtree(rt<<1,l,mid);
buildtree(rt<<1|1,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,int p,int val)///单点更新,不需要树剖
{
if(l==r)
{
tree[rt]=val;
return;
}
int mid=(l+r)>>1;
if(p<=mid) update(rt<<1,l,mid,p,val);
else update(rt<<1|1,mid+1,r,p,val);
pushup(rt);
}
int query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
return tree[rt];
}
int ans=-1;
int mid=(l+r)>>1;
if(mid>=L) ans=max(ans,query(rt<<1,l,mid,L,R));
if(mid<R) ans=max(ans,query(rt<<1|1,mid+1,r,L,R));
return ans;
}
void dfs1(int u,int faa)
{
sze[u]=1;
for(int i=head[u]; ~i; i=edge[i].nxt)
{
int v=edge[i].v;
if(v==faa) continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v,u);
sze[u]+=sze[v];
if(sze[v]>sze[son[u]]) son[u]=v;
}
}
void dfs2(int u,int Top)
{
dfn[u]=++cnt;
rk[cnt]=u;
top[u]=Top;
if(son[u]) dfs2(son[u],Top);
for(int i=head[u]; ~i; i=edge[i].nxt)
{
int v=edge[i].v;
if(v!=fa[u]&&v!=son[u])
dfs2(v,v);
}
}
int qrange(int u)///区间更新,更新u->1这条链,需要树剖
{
int v=1,ans=-1;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
ans=max(ans,query(1,1,n,dfn[top[u]],dfn[u]));
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
ans=max(ans,query(1,1,n,dfn[v],dfn[u]));
return ans;
}
bool cmp3(const E& a ,const E& b)
{
return a.w<b.w;
}
int main()
{
int t;
scanf("%d",&t);
int u,v,w,m;
while(t--)
{
scanf("%d",&n);
init();
for(int i=1; i<n; i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
e.push_back({u,v,w});
}
dfs1(1,0);
dfs2(1,1);
buildtree(1,1,n);
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
scanf("%d%d",&node[i].x,&node[i].y);
node[i].id=i;
}
sort(e.begin(),e.end(),cmp3);
sort(node+1,node+m+1,cmp1);
int j=0;
for(int i=1; i<=m; i++)
{
int x=node[i].x,y=node[i].y;
while(j<n-1){
if(e[j].w>node[i].y) break;
int c;
if(dep[e[j].u]>dep[e[j].v])///选更深的一个点u,更新u->1这条链上的最大值
c=e[j].u;
else
c=e[j].v;
update(1,1,n,dfn[c],e[j].w);
j++;
}
node[i].ans=qrange(x);
}
sort(node+1,node+m+1,cmp2);
for(int i=1;i<=m;i++)
printf("%d\n",node[i].ans);
}
return 0;
}