洛谷 P4116 Qtree3

洛谷 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\n",q_chain(1,x));
	}
	return 0;
}
posted @ 2020-10-21 14:14  Seaway-Fu  阅读(124)  评论(0编辑  收藏  举报