题目链接:https://www.spoj.com/problems/QTREE3/
大意
给一棵有
n
n
n个节点的树,树上每个节点可以是黑色或白色,起初所有节点都是白色,有Q个操作,操作的输入格式为
a
a
a
b
b
b
- a = 0 a=0 a=0时,代表改变节点 b b b的颜色
- a = 1 a=1 a=1时,代表要求输出从节点 1 1 1到节点 b b b的路径上第一个黑色的点的编号,若不存在黑色的点则输出-1。
思路
树链剖分,只不过需要维护的内容不是点权/边权而是最靠近节点
1
1
1的满足条件的节点编号。
- 细节:因为是寻找离节点 1 1 1最近的节点,所以可以以 1 1 1为根建树,查找时优先查找线段树上距离节点 1 1 1较近的一边
ac代码
#include<stdio.h>
#include<algorithm>
#define LL long long
#define N 150005
using namespace std;
int n,a,b,cot;
int p[N*2],head[N],nxt[N*2],q,val[N];
int f[N],depth[N],top[N],son[N],size[N],pos[N],cnt,A[N];
char s[20];
struct st{
LL l,r,color,min_num,exist;
};//线段树结构体
struct st dat[800020];
LL c[200020];//线段树的结构数组
void build(LL now,LL l,LL r);
void update(LL now,LL l,LL r,LL s);
inline void initialize_1(LL now,LL l);
inline void initialize_2(LL now);
inline void refresh_1(LL now,LL s);
inline void refresh_2(LL now);
void dfs1(int u,int v)
{
f[u]=v;
size[u]=1;son[u]=0;
depth[u]=depth[v]+1;
for(int i=head[u];i;i=nxt[i])
{
if(p[i]!=v)
{
dfs1(p[i],u);
size[u]+=size[p[i]];
if(size[p[i]]>size[son[u]])son[u]=p[i];
}
}
}
void dfs2(int u,int v,int to_p)
{
top[u]=to_p;
pos[u]=++cnt;
A[cnt]=val[u];
if(son[u]) dfs2(son[u],u,to_p);
for(int i=head[u];i;i=nxt[i])
{
if(p[i]!=v&&son[u]!=p[i]) dfs2(p[i],u,p[i]);
}
}
int qu(int now,int l,int r)
{
if(dat[now].l==l&&dat[now].r==r)
{
return dat[now].min_num;
}
int mid=(dat[now].l+dat[now].r)>>1;
if(l>mid)return qu(now*2+1,l,r);
else if(r<=mid)return qu(now*2,l,r);
else
{
int t1=qu(now*2,l,mid);
int t2=qu(now*2+1,mid+1,r);
if(t1!=0x7fffff)return t1;else return t2;
}
}
int query(int target)
{
int ans=0x7fffff;
while(top[target]!=1)
{
int t=qu(1,pos[top[target]],pos[target]);
if(t!=0x7fffff)
if(ans==0x7fffff||depth[ans]>depth[t])ans=t;
target=f[top[target]];
}
int t=qu(1,pos[top[target]],pos[target]);
if(t!=0x7fffff)
if(ans==0x7fffff||depth[ans]>depth[t])ans=t;
if(ans==0x7fffff)return -1;else return ans;
}
int main()
{
scanf("%d",&n); scanf("%d",&q);
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
p[++cot]=a;nxt[cot]=head[b];head[b]=cot;
p[++cot]=b;nxt[cot]=head[a];head[a]=cot;
}
dfs1(1,0);//建树,划分层次,找重儿子
dfs2(1,0,1);//分轻链重链,映射每条链至线段树
build(1,1,n);
while(q--)
{
scanf("%d%d",&a,&b);
if(!a)
{
update(1,pos[b],pos[b],b);
}
else printf("%d\n",query(b));
}
}
void build(LL now,LL l,LL r)
{
LL mid=(l+r)>>1;
dat[now].l=l;dat[now].r=r;
if(l==r)
{
initialize_1(now,l);
return;
}else
{
build(now*2,l,mid);
build(now*2+1,mid+1,r);
initialize_2(now);
return;
}
}
void update(LL now,LL l,LL r,LL s)
{
if(l==dat[now].l&&r==dat[now].r)
{
refresh_1(now,s);
return;
}
LL mid=(dat[now].l+dat[now].r)>>1;
if(l>mid){update(now*2+1,l,r,s);}else
if(r<=mid){update(now*2,l,r,s);}else
{
update(now*2,l,mid,s);
update(now*2+1,mid+1,r,s);
}
refresh_2(now);
return;
}
inline void initialize_1(LL now,LL l)
{
dat[now].color=0;dat[now].exist=0;dat[now].min_num=0x7fffff;
}
inline void initialize_2(LL now)
{
dat[now].min_num=min(dat[now*2].min_num,dat[now*2+1].min_num);
dat[now].exist=dat[now].min_num!=0x7fffff;
}
inline void refresh_1(LL now,LL s)
{
dat[now].color^=1;dat[now].exist=dat[now].color;
if(dat[now].exist) dat[now].min_num=s;else dat[now].min_num=0x7fffff;
}
inline void refresh_2(LL now)
{
if(dat[now*2].min_num!=0x7fffff)dat[now].min_num=dat[now*2].min_num;
else dat[now].min_num=dat[now*2+1].min_num;
dat[now].exist=dat[now].min_num!=0x7fffff;
}