洛谷 P4116 Qtree3
题目描述
给出N个点的一棵树(N-1条边),节点有白有黑,初始全为白
有两种操作:
0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑)
1 v : 询问1到v的路径上的第一个黑点,若无,输出-1
输入格式
第一行 N,Q,表示N个点和Q个操作
第二行到第N行N-1条无向边
再之后Q行,每行一个操作"0 i" 或者"1 v" (1 ≤ i, v ≤ N).
输出格式
对每个1 v操作输出结果
题解:
对于树上路径的题,肯定要先往树剖上想一想。
怎么做呢?
我们需要思考,如何用一棵树的树剖序+线段树来维护“最早出现”的黑点。那么这个最早出现的定义是什么呢?就是越浅越早。
??等等,越浅越早?维护最小值?
对!
我们可以把黑点的权值就赋成它的树剖序,白点的权值就赋成正无穷。那么我们就可以把这个区间查询转化成区间最小值来处理啦!
细节是树剖序、节点编号的转化。
代码:
#include<cstdio>
#include<algorithm>
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read()
{
int x=0,f=1;
char ch=nc();
while(ch<48||ch>57)
{
if(ch=='-')
f=-1;
ch=nc();
}
while(ch>=48&&ch<=57)
x=x*10+ch-48,ch=nc();
return x*f;
}
const int maxn=1e5+10;
const int INF=1e9;
int n,q;
int tot,to[maxn<<1],nxt[maxn<<1],head[maxn];
int cnt,deep[maxn],fa[maxn],size[maxn],son[maxn],top[maxn],id[maxn],fid[maxn];
int tree[maxn<<2];
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs1(int x,int f)
{
deep[x]=deep[f]+1;
fa[x]=f;
size[x]=1;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)
continue;
dfs1(y,x);
size[x]+=size[y];
if(!son[x]||size[y]>size[son[x]])
son[x]=y;
}
}
void dfs2(int x,int t)
{
top[x]=t;
id[x]=++cnt;
fid[cnt]=x;
if(!son[x])
return;
dfs2(son[x],t);
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa[x]||y==son[x])
continue;
dfs2(y,y);
}
}
void pushup(int pos)
{
tree[pos]=min(tree[lson],tree[rson]);
}
void build(int pos,int l,int r)
{
int mid=(l+r)>>1;
if(l==r)
{
tree[pos]=INF;
return;
}
build(lson,l,mid);
build(rson,mid+1,r);
pushup(pos);
}
void update(int pos,int l,int r,int x)
{
int mid=(l+r)>>1;
if(l==r)
{
tree[pos]=(tree[pos]<INF)?INF:l;
return;
}
if(x<=mid)
update(lson,l,mid,x);
else
update(rson,mid+1,r,x);
pushup(pos);
}
int query(int pos,int l,int r,int x,int y)
{
int ret=INF;
int mid=(l+r)>>1;
if(x<=l && r<=y)
return tree[pos];
if(x<=mid)
ret=min(ret,query(lson,l,mid,x,y));
if(y>mid)
ret=min(ret,query(rson,mid+1,r,x,y));
return ret;
}
int q_chain(int x,int y)
{
int ret=INF;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
ret=min(ret,query(1,1,n,id[top[x]],id[x]));
x=fa[top[x]];
}
if(deep[x]<deep[y])
swap(x,y);
ret=min(ret,query(1,1,n,id[y],id[x]));
return (ret==INF)?-1:fid[ret];
}
int main()
{
n=read();q=read();
for(int i=1;i<n;i++)
{
int x,y;
x=read();y=read();
add(x,y);
add(y,x);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=q;i++)
{
int opt,x;
opt=read();x=read();
if(!opt)
update(1,1,n,id[x]);
else
printf("%d
",q_chain(1,x));
}
return 0;
}