• 洛谷 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
    ",q_chain(1,x));
    	}
    	return 0;
    }
    
  • 相关阅读:
    今天面试一些程序员(新,老)手的体会
    UVA 10635 Prince and Princess
    poj 2240 Arbitrage
    poj 2253 Frogger
    poj 2485 Highways
    UVA 11258 String Partition
    UVA 11151 Longest Palindrome
    poj 1125 Stockbroker Grapevine
    poj 1789 Truck History
    poj 3259 Wormholes
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13852073.html
Copyright © 2020-2023  润新知