题意:

给你一棵个点的树和条路径,每条路径都有一个权值

有k组询问,每次询问给你一条路径和一个值

问你被这条路径包含的所有路径中的第K小的路径的值

题解:

我用的是树上莫队+平衡树(或分块)的方法

平衡树的话是,分块的话就是

稍微口胡一下树上莫队:

把一颗树的欧拉序搞出来,对于查询的两点(假设入栈早)。

如果是一条链,

否则,,同时莫队是要加入

平衡树有什么用?

我们看到题目中求第K大的值,就想到了用平衡树来维护值。

因为平衡树支持插入,删除和查找K大值,和莫队很配。

但其实分块更加优,分块能更好的和莫队配合。

因为分块的插入,查询,总的复杂度是(n,m同阶)

现在要处理的就是如何判断一条路径被包含,或者不被包含。

我们把每条路径看成两个点,如果这两个点都被包含,那么这条路径就是被包含的。

我们只要在莫队时记录一下每条路径两个端点被包含的个数即可。

由于同一个点可能是多条路径的端点,所以我们对每个点建一个vector,

我口胡一下分块的做法,因为更优(我一开始没想到)

先离散化,原来把值x插入平衡树(求第K大),现在就插入值域分块,

查询第K大,分块可以求出。

直接扫每一个块,扫到第一个 个数>=K的那个块停下来,再在块内暴力找。

代码:

(平衡树)

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
#define re register
int n,m,k,l,r,top,t,len;
int root,ncnt,fa[N*5],size[N*5],cnt[N*5],val[N*5],ch[N*5][2];
int a[N],ru[N],chu[N],rev[N],head[N],Ans[N],gs[N],used[N],f[N][20];
struct node{
    int l,r,id,lca,k;
}q[N];
struct node2{
    int too,next;
}edge[N];
vector<int>v[N];
char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read()
{
    int ret=0,f=0;char c=gc();
    while(!isdigit(c)){if(c=='-')f=1;c=gc();}
    while(isdigit(c)){ret=ret*10+c-48;c=gc();}
    if(f)return -ret;return ret;
}
void write(int x){
    if(x>=10) write(x/10);
    putchar(x%10+48);
}
inline void writeln(int x){
    write(x);
    putchar('\n');
}
inline bool chk(int x)
{
    return ch[fa[x]][1]==x;
}
inline void pushup(int x)
{
    size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];
}
inline void Zhuan(int x)
{
    int y=fa[x],z=fa[y],k=chk(x),w=ch[x][k^1];
    ch[y][k]=w;
    fa[w]=y;
    ch[z][chk(y)]=x;
    fa[x]=z;
    ch[x][k^1]=y;
    fa[y]=x;
    pushup(y);pushup(x);
}
inline void splay(int x,int gen=0)
{
    while(fa[x]!=gen)
    {
        int y=fa[x],z=fa[y];
        if(z!=gen)
        {
            if(chk(x)==chk(y))Zhuan(y);
            else Zhuan(x);
        }
        Zhuan(x);
    }
    if(!gen)root=x;
}
inline void insert(int x)
{
    int u=root,p=0;
    while(u&&val[u]!=x)
    {
        p=u;
        u=ch[u][x>val[u]];
    }
    if(u)cnt[u]++;
    else{
        u=++ncnt;
        fa[u]=p;
        ch[p][x>val[p]]=u;
        ch[u][0]=ch[u][1]=0;
        size[u]=cnt[u]=1;
        val[u]=x;
    }
    splay(u);
}
inline int kth(int x)
{
    int u=root;
    while(true)
    {
        if(ch[u][0]&&x<=size[ch[u][0]])u=ch[u][0];
        else if(x>size[ch[u][0]]+cnt[u])
        {
            x-=size[ch[u][0]]+cnt[u];
            u=ch[u][1];
        }
        else return u;
    }
}
inline void find(int x)
{
    int u=root;
    while(x!=val[u]&&ch[u][x>val[u]])u=ch[u][x>val[u]];
    splay(u);
}
inline int pre(int x)
{
    find(x);
    if(val[root]<x)return root;
    int u=ch[root][0];
    while(ch[u][1])u=ch[u][1];
    return u;
}
inline int nxt(int x)
{
    find(x);
    if(val[root]>x)return root;
    int u=ch[root][1];
    while(ch[u][0])u=ch[u][0];
    return u;
}
inline void Delete(int x)
{
    int last=pre(x),next=nxt(x);
    splay(last);
    splay(next,last);
    int del=ch[next][0];
    if(cnt[del]>1)
    {
        cnt[del]--;
        splay(del);
    }
    else ch[next][0]=0;
}
inline void add(int a,int b)
{
    edge[++top].too=b;edge[top].next=head[a];head[a]=top;
}
void dfs(int u,int fa)
{
    ru[u]=++t;rev[t]=u;
    f[u][0]=fa;
    for(re int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].too;
        if(v==fa)continue;
        dfs(v,u);
    }
    chu[u]=++t;rev[t]=u;
}
inline bool pd(int a,int b)
{
    if((ru[b]<=ru[a])&&(chu[b]>=chu[a]))return true;
    return false;
}
inline int LCA(int x,int y)
{
    if(pd(x,y))return y;
    if(pd(y,x))return x;
    int k=x;
    for(re int j=17;j>=0;j--)
        if((f[k][j]>0)&&(pd(y,f[k][j])==false))k=f[k][j];
    return f[k][0];
}
inline bool cmp(node a,node b)
{
    return ((a.l/len)^(b.l/len))?(a.l<b.l):((a.l/len)&1)?(a.r<b.r):(a.r>b.r);
}
inline void add(int x)
{
    for(re int i=0;i<v[x].size();i++)
    {
        gs[v[x][i]]++;
        if(gs[v[x][i]]==2)insert(a[v[x][i]]);
    }
}
inline void del(int x)
{
    for(re int i=0;i<v[x].size();i++)
    {
        gs[v[x][i]]--;
        if(gs[v[x][i]]==1)Delete(a[v[x][i]]);
    }
}
inline void Add(int x)
{
    if(used[x])del(x);
    else add(x);
    used[x]^=1;
}
int main()
{
    n=read();m=read();k=read();
    for(re int i=1;i<n;i++)
    {
        int x=read(),y=read();
        add(x,y);add(y,x);
    }
    for(re int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        a[i]=read();
        v[x].push_back(i);
        v[y].push_back(i);
    }
    dfs(1,0);
    for(re int i=1;i<=17;i++)
        for(re int j=1;j<=n;j++)
            f[j][i]=f[f[j][i-1]][i-1];
    len=sqrt(n);
    for(re int i=1;i<=k;i++)
    {
        q[i].id=i;
        int x=read(),y=read();
        q[i].k=read();
        if(ru[x]>ru[y])swap(x,y);
        int lca=LCA(x,y);
        if(lca==x)q[i].l=ru[x],q[i].r=ru[y],q[i].lca=0;
        else q[i].l=chu[x],q[i].r=ru[y],q[i].lca=lca;
    }
    sort(q+1,q+k+1,cmp);
    l=1;insert(1e9+1);insert(-1e9-1);
    for(re int i=1;i<=k;i++)
    {
        while(l>q[i].l){l--;Add(rev[l]);}
        while(r<q[i].r){r++;Add(rev[r]);}
        while(l<q[i].l){Add(rev[l]);l++;}
        while(r>q[i].r){Add(rev[r]);r--;}
        if(q[i].lca)Add(q[i].lca);
        Ans[q[i].id]=val[kth(q[i].k+1)];
        if(q[i].lca)Add(q[i].lca);
    }
    for(int i=1;i<=k;i++)writeln(Ans[i]);
    return 0;
}

(分块)

// luogu-judger-enable-o2
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
#define re register
int n,m,k,l,r,top,t,len;
int root,ncnt,size,num,xu[N],sum[N],bel[N],L[N],R[N],b[N];
int a[N],ru[N],chu[N],rev[N],head[N],Ans[N],gs[N],used[N],f[N][20];
struct node{
    int l,r,id,lca,k;
}q[N];
struct node2{
    int too,next;
}edge[N];
vector<int>v[N];
//char buf[1<<21],*p1=buf,*p2=buf;
//inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
#define gc getchar
inline int read()
{
    int ret=0,f=0;char c=gc();
    while(!isdigit(c)){if(c=='-')f=1;c=gc();}
    while(isdigit(c)){ret=ret*10+c-48;c=gc();}
    if(f)return -ret;return ret;
}
void write(int x){
    if(x>=10) write(x/10);
    putchar(x%10+48);
}
inline void writeln(int x){
    write(x);
    putchar('\n');
}
inline void insert(int x)
{
    xu[x]++;sum[bel[x]]++;
}
inline void Delete(int x)
{
    xu[x]--;sum[bel[x]]--;
}
inline void add(int a,int b)
{
    edge[++top].too=b;edge[top].next=head[a];head[a]=top;
}
void dfs(int u,int fa)
{
    ru[u]=++t;rev[t]=u;
    f[u][0]=fa;
    for(re int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].too;
        if(v==fa)continue;
        dfs(v,u);
    }
    chu[u]=++t;rev[t]=u;
}
inline bool pd(int a,int b)
{
    if((ru[b]<=ru[a])&&(chu[b]>=chu[a]))return true;
    return false;
}
inline int LCA(int x,int y)
{
    if(pd(x,y))return y;
    if(pd(y,x))return x;
    int k=x;
    for(re int j=17;j>=0;j--)
        if((f[k][j]>0)&&(pd(y,f[k][j])==false))k=f[k][j];
    return f[k][0];
}
inline bool cmp(node a,node b)
{
    return ((a.l/len)^(b.l/len))?(a.l<b.l):((a.l/len)&1)?(a.r<b.r):(a.r>b.r);
}
inline void add(int x)
{
    for(re int i=0;i<v[x].size();i++)
    {
        gs[v[x][i]]++;
        if(gs[v[x][i]]==2)insert(a[v[x][i]]);
    }
}
inline void del(int x)
{
    for(re int i=0;i<v[x].size();i++)
    {
        gs[v[x][i]]--;
        if(gs[v[x][i]]==1)Delete(a[v[x][i]]);
    }
}
inline void Add(int x)
{
    if(used[x])del(x);
    else add(x);
    used[x]^=1;
}
inline int query(int x)
{
    int i,S=0;
    for(i=1;i<=num;i++)
    {
        S+=sum[i];
        if(S>=x)break;
    }
    for(int j=R[i];j>=L[i];j--)
    {
        if(S>x-xu[j]&&S<=x)return b[j];
        S-=xu[j];
    }
}
int main()
{
    n=read();m=read();k=read();
    for(re int i=1;i<n;i++)
    {
        int x=read(),y=read();
        add(x,y);add(y,x);
    }
    for(re int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        a[i]=b[i]=read();
        v[x].push_back(i);
        v[y].push_back(i);
    }
    sort(b+1,b+m+1);
    size=unique(b+1,b+m+1)-b-1;
    for(int i=1;i<=m;i++)a[i]=lower_bound(b+1,b+size+1,a[i])-b;
    int sz=sqrt(m);
    num=m/sz;
    if(m%sz)num++;
    for(int i=1;i<=m;i++)L[i]=m+1;
    for(int i=1;i<=m;i++)
    {
        bel[i]=(i-1)/sz+1;
        L[bel[i]]=min(L[bel[i]],i);
        R[bel[i]]=max(R[bel[i]],i);
    }
    dfs(1,0);
    for(re int i=1;i<=17;i++)
        for(re int j=1;j<=n;j++)
            f[j][i]=f[f[j][i-1]][i-1];
    len=sqrt(n);
    for(re int i=1;i<=k;i++)
    {
        q[i].id=i;
        int x=read(),y=read();
        q[i].k=read();
        if(ru[x]>ru[y])swap(x,y);
        int lca=LCA(x,y);
        if(lca==x)q[i].l=ru[x],q[i].r=ru[y],q[i].lca=0;
        else q[i].l=chu[x],q[i].r=ru[y],q[i].lca=lca;
    }
    sort(q+1,q+k+1,cmp);
    l=1;
    for(re int i=1;i<=k;i++)
    {
        while(l>q[i].l){l--;Add(rev[l]);}
        while(r<q[i].r){r++;Add(rev[r]);}
        while(l<q[i].l){Add(rev[l]);l++;}
        while(r>q[i].r){Add(rev[r]);r--;}
        if(q[i].lca)Add(q[i].lca);
        Ans[q[i].id]=query(q[i].k);
        if(q[i].lca)Add(q[i].lca);
    }
    for(int i=1;i<=k;i++)writeln(Ans[i]);
    return 0;
}