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。
考虑一下题型的转化
我们可以把每个水果路径端点的dfs序提出来,将其变成一个平面内的点
然后我们考虑一个盘子(u,v)能够接到哪些水果(l,r)(我们这里令dfn[u]<dfn[v],dfn[l]<dfn[r])
如果lca为u,那么这个盘子能接到的水果的l,r需要满足
(egin{cases}1&leqslant l'<x'\v'&leqslant r'<v'+size[v]end{cases})或(egin{cases}x'+size[x]&<l'leqslant n\v'&leqslant r'<v'+size[v]end{cases})
其中,l',r'等表示dfn[l],dfn[r]...,size[v]表示以v为根的子树大小,x为v到u路径上,u的儿子节点
如果lca不为u,那么这个盘子能接到的水果的l,r需要满足
这样的话我们可以发现,每个盘子都可以表示成平面内的一个矩阵,如果有某个点在其覆盖范围内,就说明这个点,也就是这个点表示的水果能被这个矩阵表示的盘子接到
于是问题转化为了给定平面内一些点和一些带权值的矩阵,对于每个点求出覆盖其的矩阵权值的第k小
这样的话我们可以使用整体二分,当然也可以使用树套树,这里我采用后面一种写法
我们将平面中x轴排序,使用扫描线,如果使用Lazy标记的话,空间肯定开不下,因此我们采用标记永久化。
我们使用权值线段树套位置线段树,反过来的话求第(k)大较为麻烦
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Fi first
#define Se second
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
int x=0,f=1;char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
const int N=4e4,M=2e7;
int list[N+10],dfn[N+10],Ans[N+10];
int n,P,Q;
struct S1{
int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot,Time;
int fa[N+10],deep[N+10],top[N+10],Rem[N+10],size[N+10];
void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
void insert(int x,int y){join(x,y),join(y,x);}
void dfs(int x){
deep[x]=deep[fa[x]]+1,size[x]=1;
for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
if (son==fa[x]) continue;
fa[son]=x,dfs(son);
size[x]+=size[son];
if (size[Rem[x]]<size[son]) Rem[x]=son;
}
}
void build(int x){
if (!x) return;
dfn[x]=++Time;
top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
build(Rem[x]);
for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
if (son==fa[x]||son==Rem[x]) continue;
build(son);
}
}
pair<int,int> Lca(int x,int y){
int Last=0;
while (top[x]!=top[y]){
if (deep[top[x]]<deep[top[y]]) swap(x,y);
Last=top[x],x=fa[top[x]];
}
if (x==y) return make_pair(x,Last);
if (deep[x]>deep[y]) swap(x,y);
return make_pair(x,Rem[x]);
}
}HLD;//Heavy Light Decomposition
struct S2{
int root[(N<<2)+10];
struct S3{
int ls[M+10],rs[M+10],cnt[M+10],tot;
void Modify(int &p,int l,int r,int x,int y,int type){
if (!p) p=++tot;
if (x<=l&&r<=y){
cnt[p]+=type;
return;
}
int mid=(l+r)>>1;
if (x<=mid) Modify(ls[p],l,mid,x,y,type);
if (y>mid) Modify(rs[p],mid+1,r,x,y,type);
}
int Query(int p,int l,int r,int x){
if (l==r) return cnt[p];
int mid=(l+r)>>1;
if (x<=mid) return Query(ls[p],l,mid,x)+cnt[p];
else return Query(rs[p],mid+1,r,x)+cnt[p];
}
}PST;//Position Segment Tree
#define ls (p<<1)
#define rs (p<<1|1)
void Modify(int p,int l,int r,int v,int x,int y,int type){
PST.Modify(root[p],1,n,x,y,type);
if (l==r) return;
int mid=(l+r)>>1;
if (v<=mid) Modify(ls,l,mid,v,x,y,type);
else Modify(rs,mid+1,r,v,x,y,type);
}
int Query(int p,int l,int r,int k,int x){
if (l==r) return list[l];
int mid=(l+r)>>1,res=PST.Query(root[ls],1,n,x);
if (k<=res) return Query(ls,l,mid,k,x);
else return Query(rs,mid+1,r,k-res,x);
}
#undef ls
#undef rs
}PST_VST;//Position Segment Tree in Value Segment Tree
struct S4{
int x,l,r,k,type;
void insert(int _x,int _l,int _r,int _k,int _type){x=_x,l=_l,r=_r,k=_k,type=_type;}
bool operator <(const S4 &tis)const{return x<tis.x;}
}plate[(N<<3)+10];
struct S5{
int x,y,k,ID;
void insert(int _x,int _y,int _k,int _ID){x=_x,y=_y,k=_k,ID=_ID;}
bool operator <(const S5 &tis)const{return x<tis.x;}
}fruit[N+10];
int cnt;
void insert(int L,int R,int l,int r,int k){
plate[++cnt].insert(L,l,r,k,1);
plate[++cnt].insert(R+1,l,r,k,-1);
}
void Ins(int L,int R,int l,int r,int k){
if (L>R) return;
insert(L,R,l,r,k);
insert(l,r,L,R,k);
}
int main(){
n=read(),P=read(),Q=read();
for (int i=1;i<n;i++){
int x=read(),y=read();
HLD.insert(x,y);
}
HLD.dfs(1),HLD.build(1);
for (int i=1;i<=P;i++){
int x=read(),y=read(),k=read();
pair<int,int>tmp=HLD.Lca(x,y);
if (dfn[x]>dfn[y]) swap(x,y);
if (tmp.Fi==x){
Ins(1,dfn[tmp.Se]-1,dfn[y],dfn[y]+HLD.size[y]-1,k);
Ins(dfn[tmp.Se]+HLD.size[tmp.Se],n,dfn[y],dfn[y]+HLD.size[y]-1,k);
}else Ins(dfn[x],dfn[x]+HLD.size[x]-1,dfn[y],dfn[y]+HLD.size[y]-1,k);
list[i]=k;
}
sort(list+1,list+1+P);
int T=unique(list+1,list+1+P)-list-1;
for (int i=1;i<=cnt;i++) plate[i].k=lower_bound(list+1,list+1+T,plate[i].k)-list;
for (int i=1;i<=Q;i++){
int x=read(),y=read(),k=read();
if (dfn[x]>dfn[y]) swap(x,y);
fruit[i].insert(dfn[x],dfn[y],k,i);
}
sort(fruit+1,fruit+1+Q);
sort(plate+1,plate+1+cnt);
for (int i=1,j=1;i<=Q;i++){
while (j<=cnt&&plate[j].x<=fruit[i].x) PST_VST.Modify(1,1,n,plate[j].k,plate[j].l,plate[j].r,plate[j].type),j++;
Ans[fruit[i].ID]=PST_VST.Query(1,1,n,fruit[i].k,fruit[i].y);
}
for (int i=1;i<=Q;i++) printf("%d
",Ans[i]);
return 0;
}