给定一棵树,树上有 (p) 条路径,分别有权值 (c_i)。给定 (q) 个询问,每个询问给定一条路径,问所有是询问路径的子路径的树上路径中,权值第 (k) 小的是多少。(n leq 40000)
Solution
考虑一条给定路径 ((a,b)) 是询问路径 ((u,v)) 子路径的条件,不妨设 (a,u) 各自是 DFS 序较小的那个
- 如果 ((a,b)) 是直链,那么 (dfn[u] otin [dfn[x],fin[x]], dfn[v]in[dfn[b],fin[b]]),其中 (x) 是 (a) 向 (b) 走遇到的第一个点,这个可以利用倍增求出
- 如果 ((a,b)) 是弯链,那么 (dfn[u]in[dfn[a],fin[a]], dfn[v]in[dfn[b],fin[b]])
于是问题转化为二维平面上有若干个矩形,给定 (q) 个询问点,每次问覆盖这个点的所有矩形中第 (k) 小权值的矩形权值是多少
如果没有这个第 (k) 的要求,直接扫描线,线段树维护即可
现在多了 (k) 的要求,于是线段树套线段树即可,外层维护下标,内层维护权值
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
const int M = 2e7;
const int lim = 1e9;
int n,p,q,a[N],b[N],c[N],u[N],v[N],k[N],fa[N][19],dep[N],t1,t2,t3;
int dfn[N],fin[N],ind,nrect,ans[N];
vector <int> g[N];
struct point {
int x,y,k;
} pt[N];
struct rect {
int x1,y1,x2,y2,v;
} rec[N];
struct query {
int x,t,k,id;
};
struct event {
int l,r,t,v;
};
vector <query> que[N];
vector <event> evp[N],evn[N];
void dfs(int p) {
dfn[p]=++ind;
for(int i=1;i<19;i++) fa[p][i]=fa[fa[p][i-1]][i-1];
for(int q:g[p]) if(dfn[q]==0) dep[q]=dep[p]+1, fa[q][0]=p, dfs(q);
fin[p]=ind;
}
int getpoint(int p,int q) {
if(dep[p]<dep[q]) swap(p,q);
for(int i=18;i>=0;--i) if(dep[fa[p][i]]>dep[q]) p=fa[p][i];
return p;
}
namespace iseg {
int ch[M][2],a[M],ind;
void modify(int p,int l,int r,int pos,int val) {
a[p]+=val;
if(l<r) {
if(pos<=(l+r)/2) {
if(ch[p][0]==0) ch[p][0]=++ind;
modify(ch[p][0],l,(l+r)/2,pos,val);
}
else {
if(ch[p][1]==0) ch[p][1]=++ind;
modify(ch[p][1],(l+r)/2+1,r,pos,val);
}
}
}
int newnode() {
return ++ind;
}
int query(int p,int l,int r,int ql,int qr) {
if(l>qr || r<ql || p==0) return 0;
if(l>=ql&&r<=qr) return a[p];
return query(ch[p][0],l,(l+r)/2,ql,qr)+query(ch[p][1],(l+r)/2+1,r,ql,qr);
}
}
namespace oseg {
int a[M];
void modify(int p,int l,int r,int ql,int qr,int pos,int val) {
if(l>qr || r<ql) return;
if(l>=ql&&r<=qr) {
if(a[p]==0) a[p]=iseg::newnode();
iseg::modify(a[p],1,lim,pos,val);
}
else {
modify(p*2,l,(l+r)/2,ql,qr,pos,val);
modify(p*2+1,(l+r)/2+1,r,ql,qr,pos,val);
}
}
int query(int p,int l,int r,int x,int vl,int vr) {
int tmp = iseg::query(a[p],1,lim,vl,vr);
if(l==r) {
return tmp;
}
else {
if(x<=(l+r)/2) return tmp + query(p*2,l,(l+r)/2,x,vl,vr);
else return tmp + query(p*2+1,(l+r)/2+1,r,x,vl,vr);
}
}
}
namespace seq {
vector <int> a[N];
void modify(int ql,int qr,int pos) {
oseg::modify(1,1,n,ql,qr,pos,1);
}
void erase(int ql,int qr,int pos) {
oseg::modify(1,1,n,ql,qr,pos,-1);
}
int query(int x,int vl,int vr) {
return oseg::query(1,1,n,x,vl,vr);
}
int kth(int x,int k) {
int l=0,r=1e9;
while(l<r) {
int mid=(l+r)/2;
if(query(x,1,mid)>=k) r=mid;
else l=mid+1;
}
return l;
}
}
void read() {
ios::sync_with_stdio(false);
cin>>n>>p>>q;
for(int i=1;i<n;i++) {
cin>>t1>>t2;
g[t1].push_back(t2);
g[t2].push_back(t1);
}
for(int i=1;i<=p;i++) {
cin>>a[i]>>b[i]>>c[i];
}
for(int i=1;i<=q;i++) {
cin>>u[i]>>v[i]>>k[i];
}
dfs(1);
}
void make() {
for(int i=1;i<=p;i++) {
if(dfn[a[i]]>dfn[b[i]]) swap(a[i],b[i]);
if(dfn[a[i]]<=dfn[b[i]] && fin[a[i]]>=dfn[b[i]]) {
a[i]=getpoint(a[i],b[i]);
rec[++nrect]={1,dfn[b[i]],dfn[a[i]]-1,fin[b[i]],c[i]};
rec[++nrect]={fin[a[i]]+1,dfn[b[i]],n,fin[b[i]],c[i]};
}
else {
rec[++nrect]={dfn[a[i]],dfn[b[i]],fin[a[i]],fin[b[i]],c[i]};
}
}
for(int i=1;i<=q;i++) {
if(dfn[u[i]]>dfn[v[i]]) swap(u[i],v[i]);
pt[i]={dfn[u[i]],dfn[v[i]],k[i]};
}
for(int i=1;i<=nrect;i++) {
if(rec[i].x1>rec[i].x2 || rec[i].y1>rec[i].y2) continue;
evp[rec[i].y1].push_back({rec[i].x1,rec[i].x2,rec[i].y1,rec[i].v});
evn[rec[i].y2].push_back({rec[i].x1,rec[i].x2,rec[i].y2,rec[i].v});
evp[rec[i].x1].push_back({rec[i].y1,rec[i].y2,rec[i].x1,rec[i].v});
evn[rec[i].x2].push_back({rec[i].y1,rec[i].y2,rec[i].x2,rec[i].v});
}
for(int i=1;i<=q;i++) {
que[pt[i].y].push_back({pt[i].x,pt[i].y,pt[i].k,i});
}
}
void solve() {
for(int i=1;i<=n;i++) {
for(event e:evp[i]) {
seq::modify(e.l,e.r,e.v);
}
for(query q:que[i]) {
ans[q.id]=seq::kth(q.x,q.k);
}
for(event e:evn[i]) {
seq::erase(e.l,e.r,e.v);
}
}
}
void print() {
for(int i=1;i<=q;i++) cout<<ans[i]<<endl;
}
signed main() {
read();
make();
solve();
print();
}