Description
风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。
由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更
加难的版本。首先有一个地图,是一棵由 n 个顶点、n-1 条边组成的树(例如图 1
给出的树包含 8 个顶点、7 条边)。这颗树上有 P 个盘子,每个盘子实际上是一条
路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个
盘子就是顶点a_i到顶点b_i的路径(由于是树,所以从a_i到b_i的路径是唯一的),
权值为c_i。接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第
i 个水果是从顶点 u_i 到顶点v_i 的路径。幽香每次需要选择一个盘子去接当前的水
果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如
图1中从 3到7 的路径是从1到8的路径的子路径)。这里规定:从a 到b的路径与
从b到 a的路径是同一条路径。当然为了提高难度,对于第 i 个水果,你需要选择
能接住它的所有盘子中,权值第 k_i 小的那个盘子,每个盘子可重复使用(没有使用次数
的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水
果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
Input
第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。
接下来n-1 行,每行两个数 a、b,表示树上的a和b 之间有一条边。树中顶点
按1到 n标号。 接下来 P 行,每行三个数 a、b、c,表示路径为 a 到 b、权值为 c 的盘子,其
中0≤c≤10^9,a不等于b。
接下来Q行,每行三个数 u、v、k,表示路径为 u到 v的水果,其中 u不等于v,你需要选择第 k小的盘子,
第k 小一定存在。
Output
对于每个果子,输出一行表示选择的盘子的权值。
Sample Input
10 10 10
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
3 2 217394434
10 7 13022269
6 7 283254485
6 8 333042360
4 6 442139372
8 3 225045590
10 4 922205209
10 8 808296330
9 2 486331361
4 9 551176338
1 8 5
3 8 3
3 8 4
1 8 3
4 8 1
2 3 1
2 3 1
2 3 1
2 4 1
1 4 1
Sample Output
442139372
333042360
442139372
283254485
283254485
217394434
217394434
217394434
217394434
217394434
HINT
N,P,Q<=40000。
分析:
第
k
k
k小我们可以二分一个答案,再计算有多少个是他的子路径。
所以考虑整体二分,对于一个盘子(子路径),从
x
x
x到
y
y
y。假设
d
e
p
[
x
]
<
d
e
p
[
y
]
dep[x]<dep[y]
dep[x]<dep[y],如果
x
x
x是
y
y
y的父亲,那么只有一个端点在
y
y
y的子树内,另一个端点是
x
x
x的在路径上的儿子补集才满足;如果
x
x
x不是
y
y
y的父亲,那么一个端点在
x
x
x子树内,另一个端点在
y
y
y的子树内的才满足。
所以我们把从
x
x
x到
y
y
y果子(路径)看做一个点
(
d
f
n
[
x
]
,
d
f
n
[
y
]
)
(dfn[x],dfn[y])
(dfn[x],dfn[y]),对于子路径对一个矩阵+1,因为可以交换起点和终点,所以矩阵的横纵坐标交换再加一次即可。
复杂度是 O ( n l o g 3 n ) O(nlog^3n) O(nlog3n)
代码:
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
const int N=40007;
using namespace std;
int n,m,T,x,y,cnt,root;
int ls[N],dfn[N][2],dep[N],f[N][16];
struct edge{
int y,next;
}g[N*2];
struct rec{
int d[2];
};
bool operator ==(rec a,rec b)
{
return (a.d[0]==b.d[0]) && (a.d[1]==b.d[1]);
}
struct node{
int l,r,data;
}t[N*300];
struct line{
int x,y,w;
}a[N];
bool cmp1(line a,line b)
{
return a.w<b.w;
}
struct query{
int x,y,k,ans,num;
}q[N],L[N],R[N];
bool cmp2(query a,query b)
{
return a.num<b.num;
}
void add(int x,int y)
{
g[++cnt]=(edge){y,ls[x]};
ls[x]=cnt;
}
void dfs(int x,int fa)
{
dfn[x][0]=dfn[x][1]=++cnt;
f[x][0]=fa;
dep[x]=dep[fa]+1;
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if (y==fa) continue;
dfs(y,x);
dfn[x][1]=dfn[y][1];
}
}
int find(int x,int y)
{
int k=15,t=1<<k;
int d=dep[y]-dep[x]-1;
while (d)
{
if (d>=t)
{
y=f[y][k];
d-=t;
}
k--,t>>=1;
}
return y;
}
bool isfather(int x,int y)
{
return (dfn[x][0]<=dfn[y][0]) && (dfn[x][1]>=dfn[y][1]);
}
void build(int &p,rec l,rec r,rec a,int op)
{
if (!p)
{
p=++cnt;
t[p].l=t[p].r=t[p].data=0;
}
if (l==r) return;
int mid=(l.d[op]+r.d[op])/2;
rec L=l,R=r;
L.d[op]=mid+1,R.d[op]=mid;
if (a.d[op]<=mid) build(t[p].l,l,R,a,op^1);
else build(t[p].r,L,r,a,op^1);
}
void ins(int &p,rec l,rec r,rec a,rec b,int k,int op)
{
if (!p) return;
if ((l==a) && (r==b))
{
t[p].data+=k;
return;
}
int mid=(l.d[op]+r.d[op])/2;
rec L=l,R=r;
L.d[op]=mid+1,R.d[op]=mid;
if (b.d[op]<=mid) ins(t[p].l,l,R,a,b,k,op^1);
else if (a.d[op]>mid) ins(t[p].r,L,r,a,b,k,op^1);
else
{
rec A=a,B=b;
A.d[op]=mid+1,B.d[op]=mid;
ins(t[p].l,l,R,a,B,k,op^1);
ins(t[p].r,L,r,A,b,k,op^1);
}
}
int query(int &p,rec l,rec r,rec a,int op)
{
if (l==r) return t[p].data;
int mid=(l.d[op]+r.d[op])/2;
rec L=l,R=r;
L.d[op]=mid+1,R.d[op]=mid;
if (a.d[op]<=mid) return query(t[p].l,l,R,a,op^1)+t[p].data;
else return query(t[p].r,L,r,a,op^1)+t[p].data;
}
void solve(int l,int r,int ql,int qr)
{
if (ql>qr) return;
if (l==r)
{
for (int i=ql;i<=qr;i++) q[i].ans=a[l].w;
return;
}
int mid=(l+r)/2;
cnt=root=0;
for (int i=ql;i<=qr;i++)
{
int x=q[i].x,y=q[i].y;
build(root,(rec){{1,1}},(rec){{n,n}},(rec){{dfn[x][0],dfn[y][0]}},0);
}
for (int i=l;i<=mid;i++)
{
int x=a[i].x,y=a[i].y;
if (x>y) swap(x,y);
if (isfather(x,y))
{
int d=find(x,y);
if (dfn[d][0]>1) ins(root,(rec){{1,1}},(rec){{n,n}},(rec){{1,dfn[y][0]}},(rec){{dfn[d][0]-1,dfn[y][1]}},1,0);
if (dfn[d][0]>1) ins(root,(rec){{1,1}},(rec){{n,n}},(rec){{dfn[y][0],1}},(rec){{dfn[y][1],dfn[d][0]-1}},1,0);
if (dfn[d][1]<n) ins(root,(rec){{1,1}},(rec){{n,n}},(rec){{dfn[d][1]+1,dfn[y][0]}},(rec){{n,dfn[y][1]}},1,0);
if (dfn[d][1]<n) ins(root,(rec){{1,1}},(rec){{n,n}},(rec){{dfn[y][0],dfn[d][1]+1}},(rec){{dfn[y][1],n}},1,0);
}
else
{
ins(root,(rec){{1,1}},(rec){{n,n}},(rec){{dfn[x][0],dfn[y][0]}},(rec){{dfn[x][1],dfn[y][1]}},1,0);
ins(root,(rec){{1,1}},(rec){{n,n}},(rec){{dfn[y][0],dfn[x][0]}},(rec){{dfn[y][1],dfn[x][1]}},1,0);
}
}
int cnt1=0,cnt2=0;
for (int i=ql;i<=qr;i++)
{
int x=q[i].x,y=q[i].y;
int d=query(root,(rec){{1,1}},(rec){{n,n}},(rec){{dfn[x][0],dfn[y][0]}},0);
if (q[i].k<=d) L[++cnt1]=q[i];
else q[i].k-=d,R[++cnt2]=q[i];
}
for (int i=1;i<=cnt1;i++) q[ql+i-1]=L[i];
for (int i=1;i<=cnt2;i++) q[ql+cnt1+i-1]=R[i];
solve(l,mid,ql,ql+cnt1-1);
solve(mid+1,r,ql+cnt1,qr);
}
int main()
{
scanf("%d%d%d",&n,&m,&T);
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
cnt=0;
dfs(1,0);
for (int j=1;j<16;j++)
{
for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
}
for (int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
sort(a+1,a+m+1,cmp1);
for (int i=1;i<=T;i++)
{
scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].k);
q[i].num=i;
}
solve(1,m,1,T);
sort(q+1,q+T+1,cmp2);
for (int i=1;i<=T;i++) printf("%d\n",q[i].ans);
}