P4092 [HEOI2016/TJOI2016] 树
题目链接:https://www.luogu.com.cn/problem/P4092
题意:
在线查询,1.节点打上标记 2.查询给定节点打上标记的最近祖先
思路:
节点和其祖先一定在一条链上,所以转化为树链剖分+线段树的点修改和查询问题
将打标记视为+1,那么如果一条链的sum不为0,节点祖先一点在这条链上,否则跳到链顶的父亲上
为了保证祖先最近,在链上二分,每次查询一下中点左边/右边的区间sum是否不为0,如果不为0,优先取右边
int n,q;
vector<int>e[maxn];
int dep[maxn];
int son[maxn];
int dfn[maxn];
int siz[maxn];
int top[maxn];
int rk[maxn];
int l[maxn];
int r[maxn];
int f[maxn];
struct node{
int l,r;
int sum;
}tr[4*maxn];
void pushup(int p){
tr[p].sum=tr[ls].sum+tr[rs].sum;
}
void build(int p,int l,int r){
tr[p].l=l;tr[p].r=r;
if(l==r){
tr[p].sum=0;return;
}
int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
}
void add(int p,int x,int k){
if(tr[p].l==tr[p].r&&tr[p].l==x){
tr[p].sum+=k;
return;
}
int mid=tr[p].l+tr[p].r>>1;
if(x<=mid)add(ls,x,k);
else add(rs,x,k);
pushup(p);
}
int query(int p,int l,int r){
if(l<=tr[p].l&&tr[p].r<=r)return tr[p].sum;
int mid=tr[p].l+tr[p].r>>1;
int res=0;
if(l<=mid)res+=query(ls,l,r);
if(r>mid)res+=query(rs,l,r);
return res;
}
int ef(int l,int r){
if(l==r)return l;
int mid=l+r>>1;
int res=0;
if(query(1,mid+1,r))res=ef(mid+1,r);
else{
res=ef(l,mid);
}
return res;
}
void query_fa(int u){
int l=dfn[top[u]],r=dfn[u];
if(!query(1,l,r))query_fa(f[top[u]]);
else{
cout<<rk[ef(l,r)]<<endl;
}
}
void dfs1(int u,int fa){
if(u!=1){
dep[u]=dep[fa]+1;
}
f[u]=fa;
son[u]=-1;
siz[u]=1;
for(int v:e[u]){
if(v==fa)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(son[u]==-1||siz[v]>siz[son[u]])son[u]=v;
}
}
int cnt;
void dfs2(int u,int t){
dfn[u]=++cnt;
rk[cnt]=u;
top[u]=t;
l[u]=cnt;
if(son[u]==-1){
r[u]=cnt;return ;
}
dfs2(son[u],t);
for(int v:e[u]){
if(v==f[u]||v==son[u])continue;
dfs2(v,v);
}
r[u]=cnt;
}
void solve(){
cin>>n>>q;
rep(i,1,n-1){
int u,v;cin>>u>>v;
e[u].pb(v);e[v].pb(u);
}
dfs1(1,1);
dfs2(1,1);
build(1,1,n);
add(1,1,1);
while(q--){
char ch;int x;cin>>ch>>x;
if(ch=='C'){
add(1,dfn[x],1);
}else{
query_fa(x);
}
}
}

浙公网安备 33010602011771号