思路:树链剖分后用线段树维护区间中黑点出现的位置的最小值,注意下标的转换就好了
代码:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
struct edge
{
int to, next;
}Edge[N<<1];
int n, a[N], cnt, head[N], MIN[N<<2];
int top[N], son[N], f[N], size[N], id[N], rk[N], dep[N];
void add_edge(int from,int to)
{
Edge[++cnt].to = to;
Edge[cnt].next = head[from];
head[from] = cnt;
}
void dfs1(int v,int fa,int depth)
{
size[v] = 1;
f[v] = fa;
dep[v] = depth;
for(int i = head[v]; i; i = Edge[i].next){
int to = Edge[i].to;
if(to == fa) continue;
dfs1(to,v,depth+1);
size[v] += size[to];
if(size[to] > size[son[v]])
son[v] = to;
}
}
void dfs2(int v,int tp)
{
top[v] = tp;
id[v] = ++cnt;
rk[cnt] = v;
if(!son[v]) return ;
dfs2(son[v],tp);
for(int i = head[v]; i; i = Edge[i].next){
int to = Edge[i].to;
if(to == son[v] || to == f[v]) continue;
dfs2(to,to);
}
}
void pushUp(int rt)
{
MIN[rt] = min(MIN[rt<<1], MIN[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r){
MIN[rt] = N; //N代表该区间中不存在黑点
return ;
}
int m = (l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushUp(rt);
}
void update(int L,int l,int r,int rt)
{
if(l == r){
if(MIN[rt] == N) MIN[rt] = l; //由于是输出离根节点最近的点,于是直接返回点在线段树中的编号
else MIN[rt] = N; //因为对同一条链上的节点来说,在新的线段树中的节点编号越小,离根节点越近
return ;
}
int m = (l+r)>>1;
if(L <= m) update(L,l,m,rt<<1);
else update(L,m+1,r,rt<<1|1);
pushUp(rt);
}
int queryMin(int L,int R,int l,int r,int rt)
{
if(L <= l && r <= R)
return MIN[rt];
int m = (l+r)>>1, ans = N;
if(L <= m) ans = min(ans, queryMin(L,R,l,m,rt<<1));
if(m < R) ans = min(ans, queryMin(L,R,m+1,r,rt<<1|1));
return ans;
}
int queryMins(int A,int B)
{
int ans = N;
while(top[A] != top[B]){
if(dep[top[A]] < dep[top[B]]) swap(A,B);
ans = min(ans, queryMin(id[top[A]],id[A],1,n,1));
A = f[top[A]];
}
if(id[A] > id[B]) swap(A,B);
return min(ans, queryMin(id[A],id[B],1,n,1));
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int m, oper, A, B;
cin>>n>>m;
for(int i = 0; i < n-1; ++i){
cin>>A>>B;
add_edge(A,B);
add_edge(B,A);
}
cnt = 0;
dfs1(1,0,0);
dfs2(1,1);
build(1,n,1);
while(m--){
cin>>oper>>A;
if(oper == 0){
update(id[A],1,n,1);
}
else{
int t = queryMins(A,1);
if(t == N) t = -1;
if(t != -1) t = rk[t]; //记得转化为原来的编号
cout<<t<<'\n';
}
}
return 0;
}