Spoj 2798 Qtree3

时间:2019-11-14
本文章向大家介绍Spoj 2798 Qtree3,主要包括Spoj 2798 Qtree3使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一棵结点为黑色或白色的树,初始都是白色的。有两种操作 

1 将一个结点换颜色
2 询问从根到结点u路径上面的第一个黑色点,没有则输出-1
Input
In the first line there are two integers N and Q.
In the next N-1 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" (1 ≤ i, v ≤ N).
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

#include<cstdio>
#include<algorithm>
#include<cstring> 
using namespace std;const int N=200001;
int n,m,sum,cnt,now,pre[N],f[N],nxt[N],h[N],top[N],id[N],size[N],dep[N],ans,maxx,di[N];
struct oo{int a,b,dp,now;bool v;}s[N*2-20000];
void dfs(int x)
{
    size[x]=1;
    for(int i=h[x];i;i=nxt[i])
    {
        if(pre[i]==f[x])continue;
        dep[pre[i]]=dep[x]+1;
        f[pre[i]]=x;
        dfs(pre[i]);
        size[x]+=size[pre[i]];
    }
}
void dfs2(int x,int f)
{
    int k=0;
    id[x]=++cnt;
    di[cnt]=x; //dfs序中第cnt个点是x 
    top[x]=f;
    for(int i=h[x];i;i=nxt[i])
        if(size[pre[i]]>size[k]&&dep[pre[i]]>dep[x])k=pre[i];
    if(!k)return ;
    dfs2(k,f);
    for(int i=h[x];i;i=nxt[i])
        if(dep[pre[i]]>dep[x]&&pre[i]!=k)
            dfs2(pre[i],pre[i]);
}
void ins(int x,int y)
{
    pre[++now]=y;
    nxt[now]=h[x];
    h[x]=now;
}
void build(int x,int l,int r)
{
    s[x].a=l,s[x].b=r;
	s[x].dp=1e9;
    if(l==r)
	 {
			return ;
	 }
    build(x<<1,l,l+r>>1);
    build(x<<1|1,(l+r>>1)+1,r);
}
void get(int x,int l,int r)
//求出线段树上[l,r]哪个点是黑色的,且深度最小 
{
    if(s[x].a>=l&&r>=s[x].b)
    {
        if(s[x].dp<maxx)
        {
            maxx=s[x].dp; //找出深度最小值 
            sum=s[x].now;//对应的点 
        }
        return ;
    }
    else
    {
        int mid=s[x].a+s[x].b>>1;
        if(l<=mid)get(x<<1,l,r);
        if(r>mid)get(x<<1|1,l,r);
    }
}
void qmax(int x,int y)
{
    maxx=1e9,sum=-1;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])
		   swap(x,y);
        get(1,id[top[x]],id[x]);
        x=f[top[x]];
    }
    if(id[x]>id[y])
	    swap(x,y);
    get(1,id[x],id[y]);
    if(sum==0)
	   sum=-1;
}
void change(int x,int l)
//x指目前在哪个树上
//l是指线段中哪个位置 
{
    if(s[x].a==s[x].b)
    {
        s[x].v^=1;
        if(s[x].v) //如果染成黑色 
        {
            s[x].dp=dep[di[l]]; //求出深度 
            s[x].now=di[l];  
			//di[l]指dfs序列中第l个点是原树上哪个点 
        }
        else  //还原成白色 
		     s[x].dp=1e9,s[x].now=0;
        return ;
    }
    int mid=s[x].a+s[x].b>>1;
    if(l<=mid)
	   change(x<<1,l);
    else 
	    change(x<<1|1,l);
    if(s[x<<1].dp<s[x<<1|1].dp)//求出最小的深度 
    {
        s[x].dp=s[x<<1].dp;
        s[x].now=s[x<<1].now;
    }
    else
    {
        s[x].dp=s[x<<1|1].dp;
        s[x].now=s[x<<1|1].now;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        ins(x,y);
		ins(y,x);
    }
    dfs(1);
	dfs2(1,1); 
    build(1,1,n);
    int c;
    for(int i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d",&c);
        if(c) //查询操作 
        {
            scanf("%d",&b);
            qmax(1,b);
            printf("%d\n",sum);
        }
        if(!c) //将某个结点换颜色 
		   scanf("%d",&b),change(1,id[b]);
    }
}

  

 

  

原文地址:https://www.cnblogs.com/cutemush/p/11857851.html