描述
风见幽香非常喜欢玩一个叫做 osu! 的游戏,其中她最喜欢玩的模式就是接水果。由于她已经 DT FC 了 The big black, 她觉得这个游戏太简单了,于是发明了一个更加难的版本。
首先有一个地图,是一棵由 n 个顶点、n−1 条边组成的树(例如图 111 给出的树包含 888 个顶点、777 条边)。这颗树上有 P 个盘子,每个盘子实际上是一条路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个盘子就是顶点 ai 到顶点 bi 的路径(由于是树,所以从 ai 到 bi 的路径是唯一的),权值为 ci 。接下来依次会有 Q 个水果掉下来,每个水果本质上也是一条路径,第 i个水果是从顶点 ui 到顶点 vi 的路径。
幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如图 1中从 3 到 7 的路径是从 1 到 8 的路径的子路径)。这里规定:从 a 到 b 的路径与从 b 到 a 的路径是同一条路径。当然为了提高难度,对于第 i 个水果,你需要选择能接住它的所有盘子中,权值第 ki 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
输入
第一行三个数 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 小一定存在。
输出
对于每个果子,输出一行表示选择的盘子的权值。
样例输入
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
样例输出
442139372
333042360
442139372
283254485
283254485
217394434
217394434
217394434
217394434
217394434
提示
对于所有数据,N,P,Q≤40000
感觉也不是很难吧
显然可以发现题目就是在求所有被某条路径覆盖的路径的第kkk大显然 可以发现对于当前路径(u,v)(u,v)(u,v),把它覆盖的路径(x,y)(x,y)(x,y)只有2种情况
1:lca(u,v)=ulca(u,v)=ulca(u,v)=u
那么只有满足x∉Subtreeu,y∈Subtreevx\notin Subtree_u,y\in Subtree_vx∈/Subtreeu,y∈Subtreev
转化为dfsdfsdfs序即
dfn[x]∈[1,dfn[u]]⋃[dfn[u]+siz[u]−1,n]dfn[x]\in [1,{dfn[u]]\bigcup [dfn[u]+siz[u]-1},n]dfn[x]∈[1,dfn[u]]⋃[dfn[u]+siz[u]−1,n]
dfn[y]∈[dfn[v],dfn[v]+siz[v]−1]dfn[y]\in [dfn[v],dfn[v]+siz[v]-1]dfn[y]∈[dfn[v],dfn[v]+siz[v]−1]
如果把dfn[u],dfn[v]dfn[u],dfn[v]dfn[u],dfn[v]分别看成一个二维的点,那就是(dfn[x],dfn[y])(dfn[x],dfn[y])(dfn[x],dfn[y])处在2个矩形中
2:lcd(u,v)̸=ulcd(u,v)\not=ulcd(u,v)̸=u
那也就是x∈Subtreeu,y∈Subtreevx\in Subtree_u,y\in Subtree_vx∈Subtreeu,y∈Subtreev
即
dfn[x]∈[dfn[u],dfn[u]+siz[u]−1]dfn[x]\in [dfn[u],dfn[u]+siz[u]-1]dfn[x]∈[dfn[u],dfn[u]+siz[u]−1]
dfn[y]∈[dfn[v],dfn[v]+siz[v]−1]dfn[y]\in [dfn[v],dfn[v]+siz[v]-1]dfn[y]∈[dfn[v],dfn[v]+siz[v]−1]
也就是被包含在一个矩形里
那现在问题就变成了对一个点求包含它的矩形中的第kkk大
那就可以整体二分
就变成了一个二维数点问题了
扫描线+BitBitBit就可以了
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=50006;
struct plate{
int x1,x2,l1,r1,l2,r2,k;
friend inline bool operator <(const plate &a,const plate &b){
return a.k<b.k;
}
}p[N];
struct line{
int x,l,r,t;
friend inline bool operator <(const line &a,const line &b){
return a.x<b.x;
}
}p1[N<<1];
struct ask{
int x,y,k,id;
friend inline bool operator <(const ask &a,const ask &b){
return a.x<b.x;
}
}q[N],tmp[N];
struct lineask{
int x,y,p;
friend inline bool operator <(const lineask &a,const lineask &b){
return a.x<b.x;
}
}q1[N<<1];
int adj[N],nxt[N<<1],to[N<<1],dep[N],siz[N],son[N],top[N],in[N],out[N],fa[N],dfn,cnt,tot;
int ans[N],tr[N],n,m,qn,now[N];
inline void addedge(int u,int v){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
inline int lowbit(int x){
return x&(-x);
}
inline void update(int p,int k){
for(;p<=n;p+=lowbit(p))tr[p]+=k;
}
inline int query(int p,int res=0){
for(;p;p-=lowbit(p))res+=tr[p];return res;
}
inline int Lson(int u,int v){
int t;
while(top[u]!=top[v])t=top[v],v=fa[top[v]];
return u==v?t:son[u];
}
void dfs1(int u){
siz[u]=1;
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==fa[u])continue;
dep[v]=dep[u]+1,fa[v]=u;
dfs1(v),siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int tp){
in[u]=++tot,top[u]=tp;
if(son[u])dfs2(son[u],tp);
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
out[u]=tot;
}
void solve(int l,int r,int st,int des){
if(st>des)return;
if(l==r){
for(int i=st;i<=des;i++)ans[q[i].id]=p[l].k;return;
}
int mid=(l+r)>>1,cnt1=0,cnt2=0;
for(int i=l;i<=mid;i++){
if(p[i].l1<=p[i].r1){
p1[++cnt1]=(line){p[i].x1,p[i].l1,p[i].r1,1};
p1[++cnt1]=(line){p[i].x2+1,p[i].l1,p[i].r1,-1};
}
if(p[i].l2<=p[i].r2){
p1[++cnt1]=(line){p[i].x1,p[i].l2,p[i].r2,1};
p1[++cnt1]=(line){p[i].x2+1,p[i].l2,p[i].r2,-1};
}
}
for(int i=st;i<=des;i++){
q1[++cnt2]=(lineask){q[i].x,q[i].y,i};
q1[++cnt2]=(lineask){q[i].y,q[i].x,i};
now[i]=0;
}
sort(p1+1,p1+cnt1+1),sort(q1+1,q1+cnt2+1);
int j=1;
for(int i=1;i<=cnt2;i++){
while(j<=cnt1&&p1[j].x<=q1[i].x)update(p1[j].l,p1[j].t),update(p1[j].r+1,-p1[j].t),j++;
now[q1[i].p]+=query(q1[i].y);
}
int L=st,R=des;
for(int i=st;i<=des;i++)if(now[i]>=q[i].k)tmp[L++]=q[i];else q[i].k-=now[i],tmp[R--]=q[i];
for(int i=st;i<=des;i++)q[i]=tmp[i];
for(int i=1;i<j;i++)update(p1[i].l,-p1[i].t),update(p1[i].r+1,p1[i].t);
solve(l,mid,st,R),solve(mid+1,r,R+1,des);
}
int main(){
n=read(),m=read(),qn=read();
for(int i=1;i<n;i++){
int u=read(),v=read();
addedge(u,v),addedge(v,u);
}
dfs1(1),dfs2(1,1);
for(int i=1;i<=m;i++){
int u=read(),v=read(),w=read();
if(dep[u]<dep[v])swap(u,v);
if(in[v]<=in[u]&&out[u]<=out[v])v=Lson(v,u),p[i]=(plate){in[u],out[u],1,in[v]-1,out[v]+1,n,w};
else p[i]=(plate){in[u],out[u],in[v],out[v],1,0,w};
}
sort(p+1,p+m+1);
for(int i=1;i<=qn;i++){
q[i].id=i,q[i].x=in[read()],q[i].y=in[read()],q[i].k=read();
}
solve(1,m,1,qn);
for(int i=1;i<=qn;i++)cout<<ans[i]<<'\n';
}