传送门
题意:给定一个nnn个点的树,定义一个“盘子”为一个给定权值的路径,一个“水果”为一条路径,一个盘子可以接到水果当且仅当盘子的路径是水果的子路径。给出所有盘子和水果,对于每个水果求可以接它的盘子中第kik_iki小的权值。
n≤4×105n\leq 4\times10^5n≤4×105
显然这种奇奇怪怪的第kkk小考虑整体二分
给盘子按权值排序,对于一个盘子和水果的区间,要计算出每个水果可以被区间内多少个盘子接住。
根据惯用套路,把一条路径抽象成按 DFS 为坐标的点,一个盘子可以接的是一个或两个矩形中的水果。
无脑扫描线即可。因为是区间修改单点查询,可以差分后树状数组。
复杂度O(能过)O(能过)O(能过)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXN 100005
#define MAXM 200005
using namespace std;
inline int read()
{int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
struct edge{int u,v;}e[MAXM];
int head[MAXN],nxt[MAXM],cnt;
void addnode(int u,int v)
{e[++cnt]=(edge){u,v};nxt[cnt]=head[u];head[u]=cnt;
}
int dfn[MAXN],ed[MAXN],dep[MAXN],fa[MAXN][16],tim;
void dfs(int u)
{for (int i=1;i<16;i++) fa[u][i]=fa[fa[u][i-1]][i-1];dfn[u]=++tim;for (int i=head[u];i;i=nxt[i])if (!dfn[e[i].v])dep[e[i].v]=dep[u]+1,fa[e[i].v][0]=u,dfs(e[i].v);ed[u]=tim;
}
int n,p,q;
int ans[MAXN];
struct Pan{int a,b,c;}pan[MAXN];
struct fruit{int u,v,k,id;}fru[MAXN],L[MAXN],R[MAXN];
inline bool operator <(const Pan& x,const Pan& y){return x.c<y.c;}
struct node{int type,x,l,r,id;}lis[MAXM];
//trangle: +-1,x,yl,yr
//point: 0,x,y,k
inline bool operator <(const node& a,const node& b)
{if (a.x==b.x) return (unsigned)a.type>(unsigned)b.type;return a.x<b.x;
}
struct BIT
{int s[MAXN];inline int lowbit(const int& x){return x&-x;}inline void modify(int x,int v){for (;x<=n;s[x]+=v,x+=lowbit(x));}inline int query(int x,int ans=0){for (;x;ans+=s[x],x-=lowbit(x));return ans;}
}bit;
void solve(int l,int r,int vl,int vr)
{if (l>r||vl>vr) return;if (vl==vr){for (int i=l;i<=r;i++) ans[fru[i].id]=pan[vl].c;return;}int vmid=(vl+vr)>>1;int tot=0;for (int i=vl;i<=vmid;i++){int u=pan[i].a,v=pan[i].b;if (dfn[v]<=ed[u]){int t=dep[v]-dep[u]-1;u=v;for (int i=0;(1<<i)<=t;i++) if (t&(1<<i)) u=fa[u][i];lis[++tot]=(node){1,1,dfn[v],ed[v],0};lis[++tot]=(node){-1,dfn[u],dfn[v],ed[v],0};lis[++tot]=(node){1,dfn[v],ed[u]+1,n,0};lis[++tot]=(node){-1,ed[v]+1,ed[u]+1,n,0};}else{lis[++tot]=(node){1,dfn[u],dfn[v],ed[v],0};lis[++tot]=(node){-1,ed[u]+1,dfn[v],ed[v],0};}}for (int i=l;i<=r;i++) lis[++tot]=(node){0,dfn[fru[i].u],dfn[fru[i].v],fru[i].k,i};sort(lis+1,lis+tot+1);int lcnt=0,rcnt=0;for (int i=1;i<=tot;i++){if (lis[i].type) bit.modify(lis[i].l,lis[i].type),bit.modify(lis[i].r+1,-lis[i].type);else{int k=bit.query(lis[i].l);if (lis[i].r<=k) L[++lcnt]=fru[lis[i].id];else fru[lis[i].id].k-=k,R[++rcnt]=fru[lis[i].id];}}for (int i=l;i<=l+lcnt-1;i++) fru[i]=L[i-l+1];for (int i=l+lcnt;i<=r;i++) fru[i]=R[i-l-lcnt+1];solve(l,l+lcnt-1,vl,vmid);solve(l+lcnt,r,vmid+1,vr);
}
int main()
{n=read(),p=read(),q=read();for (int i=1;i<n;i++){int u,v;u=read(),v=read();addnode(u,v),addnode(v,u);}dep[1]=1,dfs(1);for (int i=1;i<=p;i++) {pan[i].a=read(),pan[i].b=read(),pan[i].c=read();if (dfn[pan[i].a]>dfn[pan[i].b]) swap(pan[i].a,pan[i].b);}sort(pan+1,pan+p+1);for (int i=1;i<=q;i++){fru[i].u=read(),fru[i].v=read(),fru[i].k=read(),fru[i].id=i;if (dfn[fru[i].u]>dfn[fru[i].v]) swap(fru[i].u,fru[i].v);}solve(1,q,1,p);for (int i=1;i<=q;i++) printf("%d\n",ans[i]);return 0;
}