题意:
有一颗大小为\(n\)的树,给定\(m\)条固定路径,再给定\(q\)条查询路径,求每条查询路径上第\(k\)大的固定路径
范围&性质:\(1\le n,m,q\le 4\times10^4\)
分析:
我们将问题拆成两部分,求每条询问路径上有几条固定路径,求一个固定路径集合中第\(k\)大的路径
我们发现前一部分可以用树上莫队解决,后一部分可以用分块解决,好像这道题就能做了
QED.
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
typedef long long ll;
const int maxn = 2e6+5;
ll n,m,q,cnt=0,idx=0,l,r,sz,num,block,size;
ll head[maxn],sum[maxn],line[maxn],bel[maxn],gs[maxn],fa[maxn][25],in[maxn],id[maxn],out[maxn];
ll a[maxn],b[maxn],dep[maxn],L[maxn],R[maxn],ans[maxn];
bool vis[maxn];
vector<ll> v[maxn];
struct node
{
ll l,r,id,k,lca;
}Q[maxn];
bool cmp1(node a,node b)
{
return (a.l/block)^(b.l/block)?(a.l<b.l):((a.l/block)&1)?(a.r<b.r):(a.r>b.r);
}
struct edge
{
ll to,nxt;
}e[maxn<<1];
void add(ll u,ll v)
{
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs(ll u,ll ff)
{
fa[u][0]=ff;
dep[u]=dep[ff]+1;
in[u]=++idx;
id[idx]=u;
for(ll i=head[u];i;i=e[i].nxt)
{
ll v=e[i].to;
if(v==ff) continue;
dfs(v,u);
}
out[u]=++idx;
id[idx]=u;
}
ll lca(ll x,ll y)
{
if(dep[x]<dep[y]) swap(x,y);
for(ll i=20;i>=0;i--)
{
if(dep[fa[x][i]]>=dep[y])
{
x=fa[x][i];
}
}
if(x==y) return x;
for(ll i=20;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
void Insert(ll x)
{
gs[x]++;
sum[bel[x]]++;
}
void Delete(ll x)
{
gs[x]--;
sum[bel[x]]--;
}
void add(ll pos)
{
for(ll i=0;i<(ll)v[pos].size();i++)
{
line[v[pos][i]]++;
if(line[v[pos][i]]==2) Insert(a[v[pos][i]]);
}
}
void del(ll pos)
{
for(ll i=0;i<(ll)v[pos].size();i++)
{
line[v[pos][i]]--;
if(line[v[pos][i]]==1) Delete(a[v[pos][i]]);
}
}
void move(ll pos)
{
if(vis[pos]) del(pos);
else add(pos);
vis[pos]^=1;
}
ll query(ll k)
{
ll i,res=0;
for(i=1;i<=num;i++)
{
res+=sum[i];
if(res>=k) break;
}
for(ll j=R[i];j>=L[i];j--)
{
if(res>k-gs[j]&&res<=k) return b[j];
res-=gs[j];
}
}
void work()
{
ll x,y;
scanf("%lld%lld%lld",&n,&m,&q);
for(ll i=1;i<n;i++)
{
scanf("%lld%lld",&x,&y);
add(x,y);
add(y,x);
}
for(ll i=1;i<=m;i++)
{
scanf("%lld%lld",&x,&y);
scanf("%lld",&a[i]);b[i]=a[i];
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(ll i=1;i<=m;i++)
{
a[i]=lower_bound(b+1,b+size+1,a[i])-b;
}
sz=sqrt(m);
num=m/sz;
if(m%sz) num++;
for(ll i=1;i<=m;i++) L[i]=m+1;
for(ll 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(ll i=1;i<=18;i++)
{
for(int j=1;j<=n;j++)
{
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
block=pow(idx,2.0/3.0);
for(ll i=1;i<=q;i++)
{
Q[i].id =i;
scanf("%lld%lld%lld",&x,&y,&Q[i].k);
if(in[x]>in[y]) swap(x,y);
ll tmp=lca(x,y);
if(tmp==x) Q[i].lca=0,Q[i].l=in[x],Q[i].r=in[y];
else Q[i].lca=tmp,Q[i].l=out[x],Q[i].r=in[y];
}
sort(Q+1,Q+q+1,cmp1);
l=1;
for(ll i=1;i<=q;i++)
{
while(l>Q[i].l) move(id[--l]);
while(r<Q[i].r) move(id[++r]);
while(l<Q[i].l) move(id[l++]);
while(r>Q[i].r) move(id[r--]);
if(Q[i].lca) move(Q[i].lca);
ans[Q[i].id]=query(Q[i].k);
if(Q[i].lca) move(Q[i].lca);
}
for(ll i=1;i<=q;i++)
{
printf("%lld\n",ans[i]);
}
}
}
int main()
{
zzc::work();
return 0;
}