題意
給你一棵 個點的樹和 條路徑,每條路徑有權值。接下來有 次詢問,每次再給出一條路徑,詢問這條路徑完全覆蓋的路徑中權值第 小的路徑權值。
做法
考慮路徑 會被哪些路徑完全覆蓋,那麼就有兩種情況:
1、 是 的祖先,那麼完全覆蓋它的路徑 滿足 , ,其中 表示 序, 表示子樹中最大的 。
2、 不是 的祖先,那麼 滿足 , 。
可以發現,完全覆蓋這條路徑的點對集合構成了一個或兩個矩形。
算法一
根本不會整體二分,那麼可以把這些矩形按權值從小到大添加進樹套樹,然後詢問的時候二分答案在樹套樹上走一下就可以了。
時間複雜度: ,在各大OJ上都是 。
算法二
每次詢問都是相同的二分,所以可以考慮整體二分,每次二分一個 。將 的矩形加進去,同時判斷每個詢問是要往 走還是 走,用一個掃描線從左往右掃,每一列用樹狀數組維護就行了。
時間複雜度: 。
代碼
#include<bits/stdc++.h>
using namespace std;
#define REP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i<=i##end;++i)
#define DREP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i>=i##end;--i)
template<typename T>bool chkmin(T &x,const T &y){return x>y?x=y,1:0;}
template<typename T>bool chkmax(T &x,const T &y){return x<y?x=y,1:0;}
#ifdef __linux__
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
template<typename T>T read(){
T x=0,f=1;
char c=getchar();
while((c<'0')||(c>'9')){if(c=='-')f=-1;c=getchar();}
while((c>='0')&&(c<='9'))x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
#define read() read<int>()
template<typename T>void write(T x,char c){
static char t[25];
static int tlen;
t[tlen=1]=c;
if(x<0)putchar('-'),x=-x;
do t[++tlen]=(x%10)^48;
while(x/=10);
while(tlen)putchar(t[tlen--]);
}
#define pb push_back
typedef long long ll;
typedef double lf;
const int maxn=40005;
struct data{
int u,v,w;
bool operator < (const data &A) const {
return w<A.w;
}
}q[maxn];
int n,m,q_cnt;
int fa[maxn][16],dep[maxn];
int Root[maxn];
vector<int>E[maxn];
int dfn[maxn],edn[maxn],dfs_clock;
void DFS(int u){
dfn[u]=++dfs_clock;
REP(i,0,E[u].size()-1){
int v=E[u][i];
if(v==fa[u][0])continue;
fa[v][0]=u;
REP(j,1,15)fa[v][j]=fa[fa[v][j-1]][j-1];
dep[v]=dep[u]+1;
DFS(v);
}
edn[u]=dfs_clock;
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
DREP(k,15,0)if(dep[fa[u][k]]>=dep[v])u=fa[u][k];
if(u==v)return u;
DREP(k,15,0)if(fa[u][k]!=fa[v][k])u=fa[u][k],v=fa[v][k];
return fa[u][0];
}
int tot;
struct node{int lc,rc,val,tag;};
struct seg_tree{
node tr[maxn*600];
void update_y(int &p,int lst,int l,int r,int L,int R,int tag){
if((!p)||(tr[p].tag!=tag))tr[p=++tot]=tr[lst],tr[p].tag=tag;
if((L<=l)&&(R>=r)){tr[p].val++;return;}
int mid=(l+r)>>1;
if(L<=mid)update_y(tr[p].lc,tr[lst].lc,l,mid,L,R,tag);
if(R>mid)update_y(tr[p].rc,tr[lst].rc,mid+1,r,L,R,tag);
}
void update(int &p,int lst,int l,int r,int L,int R,int L1,int R1,int tag){
if((!p)||(tr[p].tag!=tag))tr[p=++tot]=tr[lst],tr[p].tag=tag;
if((L<=l)&&(R>=r))return update_y(tr[p].val,tr[lst].val,1,n,L1,R1,tag);
int mid=(l+r)>>1;
if(L<=mid)update(tr[p].lc,tr[lst].lc,l,mid,L,R,L1,R1,tag);
if(R>mid)update(tr[p].rc,tr[lst].rc,mid+1,r,L,R,L1,R1,tag);
}
int query_y(int p,int l,int r,int pos){
if(!p)return 0;
int res=tr[p].val;
if(l==r)return res;
int mid=(l+r)>>1;
if(pos<=mid)res+=query_y(tr[p].lc,l,mid,pos);
else res+=query_y(tr[p].rc,mid+1,r,pos);
return res;
}
int query(int p,int l,int r,int pos,int pos_y){
if(!p)return 0;
int res=query_y(tr[p].val,1,n,pos_y);
if(l==r)return res;
int mid=(l+r)>>1;
if(pos<=mid)res+=query(tr[p].lc,l,mid,pos,pos_y);
else res+=query(tr[p].rc,mid+1,r,pos,pos_y);
return res;
}
}T;
int now,lst;
void Update(int L1,int R1,int L2,int R2,int id){
if((L1>R1)||(L2>R2))return;
T.update(Root[id],Root[id-1],1,n,L1,R1,L2,R2,id);
T.update(Root[id],Root[id-1],1,n,L2,R2,L1,R1,id);
}
int Query(int id,int u,int v){
if(u==v)return T.query(id,1,n,u,v)/2;
else return T.query(id,1,n,u,v);
}
int find_fa(int u,int dep){
DREP(k,15,0)if((1<<k)<=dep)u=fa[u][k],dep-=(1<<k);
return u;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("ans.txt","w",stdout);
#endif
int u,v,w;
n=read(),m=read(),q_cnt=read();
REP(i,1,n-1){
u=read(),v=read();
E[u].pb(v),E[v].pb(u);
}
dep[1]=1,DFS(1);
REP(i,1,m){
u=read(),v=read(),w=read();
q[i]=(data){u,v,w};
}
sort(q+1,q+1+m);
REP(i,1,m){
u=q[i].u,v=q[i].v,w=lca(u,v);
if(dep[u]>dep[v])swap(u,v);
if(u==w){
int t=find_fa(v,dep[v]-dep[u]-1);
Update(dfn[v],edn[v],1,dfn[t]-1,i);
Update(dfn[v],edn[v],edn[t]+1,n,i);
}else Update(dfn[u],edn[u],dfn[v],edn[v],i);
}
REP(i,1,q_cnt){
u=read(),v=read(),w=read();
int l=1,h=m;
while(l<=h){
int mid=(l+h)>>1;
if(Query(Root[mid],dfn[u],dfn[v])>=w)h=mid-1;
else l=mid+1;
}write(q[l].w,'\n');
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
#define REP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i<=i##end;++i)
#define DREP(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i>=i##end;--i)
template<typename T>bool chkmin(T &x,const T &y){return x>y?x=y,1:0;}
template<typename T>bool chkmax(T &x,const T &y){return x<y?x=y,1:0;}
#ifdef __linux__
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
template<typename T>T read(){
T x=0,f=1;
char c=getchar();
while((c<'0')||(c>'9')){if(c=='-')f=-1;c=getchar();}
while((c>='0')&&(c<='9'))x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
#define read() read<int>()
template<typename T>void write(T x,char c){
static char t[25];
static int tlen;
t[tlen=1]=c;
if(x<0)putchar('-'),x=-x;
do t[++tlen]=(x%10)^48;
while(x/=10);
while(tlen)putchar(t[tlen--]);
}
#define pb push_back
typedef long long ll;
typedef double lf;
const int maxn=40005;
int n,m,q_cnt;
int fa[maxn][16],dep[maxn];
vector<int>E[maxn];
int dfn[maxn],edn[maxn],dfs_clock;
void DFS(int u){
dfn[u]=++dfs_clock;
REP(i,0,E[u].size()-1){
int v=E[u][i];
if(v==fa[u][0])continue;
fa[v][0]=u;
REP(j,1,15)fa[v][j]=fa[fa[v][j-1]][j-1];
dep[v]=dep[u]+1;
DFS(v);
}
edn[u]=dfs_clock;
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
DREP(k,15,0)if(dep[fa[u][k]]>=dep[v])u=fa[u][k];
if(u==v)return u;
DREP(k,15,0)if(fa[u][k]!=fa[v][k])u=fa[u][k],v=fa[v][k];
return fa[u][0];
}
int find_fa(int u,int dep){
DREP(k,15,0)if((1<<k)<=dep)u=fa[u][k],dep-=(1<<k);
return u;
}
struct segment{
int pos,l,r,x;
bool operator < (const segment &A) const {
return pos<A.pos;
}
};
struct data{
int u,v,w;
vector<segment>s;
bool operator < (const data &A) const {
return w<A.w;
}
}t[maxn];
struct Query{
int u,v,k,id,pre;
bool operator < (const Query &A) const {
return u<A.u;
}
}q[maxn],tmp[maxn];
int ans[maxn];
vector<segment>G;
namespace bitree{
int c[maxn];
void update(int x,int val){
while(x<=n)
c[x]+=val,x+=x&-x;
}
int query(int x){
int res=0;
while(x)
res+=c[x],x-=x&-x;
return res;
}
}
using namespace bitree;
void solve(int l,int r,int L,int R){
if((l==r)||(L>R)){
REP(i,L,R)
ans[q[i].id]=t[l].w;
return;
}
int mid=(l+r)>>1;
G.clear();
REP(i,l,mid)
REP(j,0,t[i].s.size()-1)G.pb(t[i].s[j]);
sort(G.begin(),G.end());
int cur=L,curl=L,curr=R;
REP(i,0,G.size()-1){
while((cur<=R)&&(q[cur].u<G[i].pos)){
int x=query(q[cur].v);
if(q[cur].pre+x>=q[cur].k)tmp[curl]=q[cur],++curl;
else tmp[curr]=q[cur],tmp[curr].pre+=x,--curr;
++cur;
}
update(G[i].l,G[i].x);
update(G[i].r+1,-G[i].x);
}
while(cur<=R){
int x=query(q[cur].v);
if(q[cur].pre+x>=q[cur].k)tmp[curl]=q[cur],++curl;
else tmp[curr]=q[cur],tmp[curr].pre+=x,--curr;
++cur;
}
REP(i,L,curl-1)q[i]=tmp[i];
REP(i,curl,R)q[i]=tmp[R-i+curl];
solve(l,mid,L,curl-1);
solve(mid+1,r,curl,R);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int u,v,w;
n=read(),m=read(),q_cnt=read();
REP(i,1,n-1){
u=read(),v=read();
E[u].pb(v),E[v].pb(u);
}
dep[1]=1,DFS(1);
REP(i,1,m){
u=read(),v=read(),w=read();
t[i]=(data){u,v,w};
}
sort(t+1,t+1+m);
REP(i,1,m){
u=t[i].u,v=t[i].v,w=lca(u,v);
if(dfn[u]>dfn[v])swap(u,v);
if(u==w){
w=find_fa(v,dep[v]-dep[u]-1);
if(dfn[w]>1){
t[i].s.pb((segment){1,dfn[v],edn[v],1});
t[i].s.pb((segment){dfn[w],dfn[v],edn[v],-1});
}
if(edn[w]<n){
t[i].s.pb((segment){dfn[v],edn[w]+1,n,1});
t[i].s.pb((segment){edn[v]+1,edn[w]+1,n,-1});
}
}else{
t[i].s.pb((segment){dfn[u],dfn[v],edn[v],1});
t[i].s.pb((segment){edn[u]+1,dfn[v],edn[v],-1});
}
}
REP(i,1,q_cnt){
u=read(),v=read(),w=read();
if(dfn[u]>dfn[v])swap(u,v);
q[i]=(Query){dfn[u],dfn[v],w,i};
}
sort(q+1,q+1+q_cnt);
solve(1,m,1,q_cnt);
REP(i,1,q_cnt)
write(ans[i],'\n');
return 0;
}