保护
给出一棵树,若干条树上路径。若干次询问某一点到根的路径上,被覆盖次数大于等于k的点的最浅深度。
把lca标记打到x点和y点的深度线段树上,那么从下往上线段树合并即可。当然,用主席树从上往下合并也可。
#include <cstdio>
#include <vector>
using namespace std;
const int maxn=2e5+5;
int n, m, Q;
int fir[maxn], cnte;
struct Edge{
int to, nxt;
}e[maxn*2];
void addedge(int x, int y){
Edge &ed=e[++cnte];
ed.to=y; ed.nxt=fir[x]; fir[x]=cnte; }
int euler[maxn*2], ftim[maxn], tim, st[maxn*2][20], dep[maxn];
void predfs(int u, int p){ int v;
ftim[u]=tim; euler[tim++]=u; dep[u]=dep[p]+1;
for (int i=fir[u]; i; i=e[i].nxt){
if ((v=e[i].to)==p) continue;
predfs(v, u); euler[tim++]=u; }
}
int lca(int x, int y){
x=ftim[x]; y=ftim[y];
if (x>y) swap(x, y); int c=-1;
for (int l=y-x+1; l; l>>=1) ++c; //这里求的是l是2的几次
if (dep[st[x][c]]<dep[st[y-(1<<c)+1][c]]) return st[x][c];
else return st[y-(1<<c)+1][c];
}
int cntn, rt[maxn*2*20], lc[maxn*2*20], rc[maxn*2*20], seg[maxn*2*20];
void ins(int &x, int l, int r, int p){
if (!x) x=++cntn; ++seg[x];
if (l==r) return; int mid=(l+r)>>1;
if (mid>=p) ins(lc[x], l, mid, p);
else ins(rc[x], mid+1, r, p);
}
int merge(int x, int y){ //把y合并到x上
//最底层的点是代表x和y最底层的和的 然后可以归纳法证明
if (!x) return y; if (!y) return x;
seg[x]+=seg[y];
lc[x]=merge(lc[x], lc[y]);
rc[x]=merge(rc[x], rc[y]);
return x;
}
int query(int x, int l, int r, int k){
if (l==r) return l; int mid=(l+r)>>1;
if (seg[lc[x]]>=k) return query(lc[x], l, mid, k);
else return query(rc[x], mid+1, r, k-seg[lc[x]]);
}
vector<int> q[maxn], id[maxn]; int ans[maxn];
void dfs(int u, int p){ int v;
for (int j=fir[u]; j; j=e[j].nxt){
if ((v=e[j].to)==p) continue;
dfs(v, u); merge(rt[u], rt[v]);
}
for (int i=0; i<q[u].size(); ++i)
ans[id[u][i]]=dep[u]-query(rt[u], 1, n, q[u][i]);
}
int main(){
scanf("%d%d", &n, &m); int x, y, Lca;
for (int i=1; i<n; ++i){
scanf("%d%d", &x, &y);
addedge(x, y); addedge(y, x); }
dep[1]=1; predfs(1, 0); dep[0]=1e9;
for (int i=0; i<tim; ++i) st[i][0]=euler[i];
for (int i=1; i<20; ++i)
for (int j=0; j<tim; ++j)
if (dep[st[j][i-1]]<dep[st[j+(1<<i-1)][i-1]])
st[j][i]=st[j][i-1];
else st[j][i]=st[j+(1<<i-1)][i-1];
for (int i=1; i<=n; ++i) rt[++cntn]=i;
for (int i=1; i<=m; ++i){
scanf("%d%d", &x, &y); Lca=lca(x, y);
ins(rt[x], 1, n, dep[Lca]); ins(rt[y], 1, n, dep[Lca]);
}
scanf("%d", &Q);
for (int i=1; i<=Q; ++i){
scanf("%d%d", &x, &y);
q[x].push_back(y); id[x].push_back(i); }
dfs(1, 0);
for (int i=1; i<=Q; ++i) printf("%d
", ans[i]<0?0:ans[i]);
return 0;
}