Spoj2798 Qtree3

Description
You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are numbered from 1 to N. In the start, the color of any node in the tree is white.
We will ask you to perfrom some instructions of the following form:
0 i : change the color of the i-th node (from white to black, or from black to white);
or
1 v : ask for the id of the first black node on the path from node 1 to node v.
if it doesn’t exist, you may return -1 as its result.

Input
In the first line there are two integers N and Q.
In the next N1 lines describe the edges in the tree: a line with two integers a b denotes an edge between a and b. The next Q lines contain instructions “0 i” or “1 v (1i,vN).

Output
For each “1 v ” operation, write one integer representing its result.

Sample Input
9 8
1 2
1 3
2 4
2 9
5 9
7 9
8 9
6 8
1 3
0 8
1 6
1 7
0 2
1 9
0 2
1 9

Sample Output
-1
8
-1
2
-1

题目解释
一棵结点为黑色或白色的树,初始都是白色的。有两种操作。
1. 将一个结点换颜色。
2. 询问从根到结点u路径上面的第一个黑色点,没有则输出-1。

思路
还是一道树链剖分水题,只是。。。只是线段树要多处理一下。每一段连续的区间存的是最小的黑色节点。如果没有黑色节点则赋值为 inf 。没了。

代码

#include <cstdio>
#include <algorithm>
#include <cstring>

const int maxn=100000;
const int inf=1000000000;

struct sigment_tree
{
    int val[(maxn<<2)+10];

    int updata(int now)
    {
        val[now]=std::min(val[now<<1],val[now<<1|1]);
        return 0;
    }

    int build(int now,int left,int right)
    {
        if(left==right)
        {
            val[now]=inf;
            return 0;
        }
        int mid=(left+right)>>1;
        build(now<<1,left,mid);
        build(now<<1|1,mid+1,right);
        updata(now);
        return 0;
    }

    int modify(int now,int left,int right,int findnum)
    {
        if((left>findnum)||(right<findnum))
        {
            return 0;
        }
        if(left==right)
        {
            if(val[now]==inf)
            {
                val[now]=left;
            }
            else
            {
                val[now]=inf;
            }
            return 0;
        }
        int mid=(left+right)>>1;
        modify(now<<1,left,mid,findnum);
        modify(now<<1|1,mid+1,right,findnum);
        updata(now);
        return 0;
    }

    int ask(int now,int left,int right,int askl,int askr)
    {
        if((askr<left)||(right<askl))
        {
            return inf;
        }
        if((askl<=left)&&(right<=askr))
        {
            return val[now];
        }
        int mid=(left+right)>>1;
        return std::min(ask(now<<1,left,mid,askl,askr),ask(now<<1|1,mid+1,right,askl,askr));
    }
};

int n;

struct tree
{
    int pre[(maxn<<1)+10],now[maxn+10],son[(maxn<<1)+10],tot,cntpos[maxn+10];
    int fa[maxn+10],wson[maxn+10],size[maxn+10],deep[maxn+10],top[maxn+10],dfn[maxn+10],cnt;
    sigment_tree st;

    int ins(int a,int b)
    {
        tot++;
        pre[tot]=now[a];
        now[a]=tot;
        son[tot]=b;
        return 0;
    }

    int first_dfs(int u,int father)
    {
        fa[u]=father;
        size[u]=1;
        deep[u]=deep[father]+1;
        wson[u]=0;
        int j=now[u];
        while(j)
        {
            int v=son[j];
            if(v!=father)
            {
                first_dfs(v,u);
                size[u]+=size[v];
                if((!wson[u])||(size[wson[u]]<size[v]))
                {
                    wson[u]=v;
                }
            }
            j=pre[j];
        }
        return 0;
    }

    int second_dfs(int u,int father,int topfather)
    {
        top[u]=topfather;
        cnt++;
        dfn[u]=cnt;
        cntpos[cnt]=u;
        if(wson[u])
        {
            second_dfs(wson[u],u,topfather);
        }
        int j=now[u];
        while(j)
        {
            int v=son[j];
            if((v!=father)&&(v!=wson[u]))
            {
                second_dfs(v,u,v);
            }
            j=pre[j];
        }
        return 0;
    }

    int change(int pos)
    {
        st.modify(1,1,n,dfn[pos]);
        return 0;
    }

    int query(int x,int y)
    {
        int res=inf;
        while(top[x]!=top[y])
        {
            if(deep[top[x]]<deep[top[y]])
            {
                std::swap(x,y);
            }
            res=std::min(res,st.ask(1,1,n,dfn[top[x]],dfn[x]));
            x=fa[top[x]];
        }
        if(deep[x]>deep[y])
        {
            std::swap(x,y);
        }
        res=std::min(res,st.ask(1,1,n,dfn[x],dfn[y]));
        if(res==inf)
        {
            return -1;
        }
        return cntpos[res];
    }
};

tree t;
int m;

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<n; i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        t.ins(a,b);
        t.ins(b,a);
    }
    t.st.build(1,1,n);
    t.first_dfs(1,0);
    t.second_dfs(1,0,1);
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(a)
        {
            printf("%d\n",t.query(1,b));
        }
        else
        {
            t.change(b);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值