zoukankan      html  css  js  c++  java
  • 洛谷 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;
    }
    
  • 相关阅读:
    Linux之lsof命令
    lnmp一键安装的卸载
    MySQL密码忘了怎么办?MySQL重置root密码方法
    LNMP状态管理命令
    perl5 第一章 概述
    行政级别详解
    http://dl.fedoraproject.org/pub/epel/7/x86_64/,开源软件清单list
    Linux Centos 系统上安装BT客户端 Transmission
    在VPS上安裝BT軟體Transmission
    What is a good EPUB reader on Linux
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13852073.html
Copyright © 2011-2022 走看看