黑白树

问题 B: 黑白树

时间限制: 2 Sec   内存限制: 512 MB
提交: 75   解决: 45
[ 提交][ 状态][ 讨论版]

题目描述

给定一棵树,边的颜色为黑或白,初始时全部为白色。维护两个操作:
 
 
1.查询u到根路径上的第一条黑色边的标号。
2.将u到v    路径上的所有边的颜色设为黑色。
 
Notice:这棵树的根节点为1

输入


第一行两个数n,m分别表示点数和操作数。
接下来n-?    1行,每行2个数u,v.表示一条u到v的边。
接下来m行,每行为以下格式:
 
 
1 v 表示第一个操作
 
 
2 v u 表示第二种操作
 
 

输出

对于每个询问,输出相应答案。如果不存在,输出0。

样例输入

5 4
1 2
1 3
2 4
2 5
1 2
2 2 3
1 3
1 4
 

样例输出

0
2
1
 


黑白树

         既然上面都乱搞压正解了那这道怎能不暴力出奇迹,是的正解暴力。考试的时候看出是树剖裸题,但之前都没看啊,于是乎用尽毕生所学,根据理解和残存的记忆打出了树剖,嗯打对了,但正解不是树剖……

         不过还是有安慰奖的,水过了80分,总比没有好。

         据传正解是并查集加树剖,不过我们有更强悍的暴力,正解都有可能T,还是暴力靠谱。既然都是暴力了,那也就没什么技术含量了,纯朴素算法。


#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#define V 2000200
using namespace std;
int n,m;
struct data
{
     int to,next,id;  
}Edge[2*V];
int head[V],dep[V],sd[V],tot,tt,sz[V],tz;
int f[V];
inline void add1( int x, int y, int z)
{
   Edge[tot].id=z;
   Edge[tot].to=y;
   Edge[tot].next=head[x];
   head[x]=tot++;      
}
inline void dfs( int x)
{
    int v;
    for ( int i=head[x];i!=-1;i=Edge[i].next)
    {
       v=Edge[i].to;
       if (v==f[x]) continue ;
       f[v]=x;
       sd[v]=Edge[i].id;
       sz[v]=0;
       dep[v]=dep[x]+1;
       dfs(v);
    }   
}
inline void U( int x, int y)
{
  // int fx=f[x],fy=x[y];
   if (dep[x]<dep[y])
   swap(x,y);
   while (x!=y)
   {
      //cout<<x<<" "<<y<<endl;
      while (dep[x]>=dep[y]&&x!=y)
      {
      // cout<<x<<" "<<y<<endl;
          sz[x]=1;
          x=f[x];
      }
      swap(x,y);
   }
}
int Q( int x)
{
     while (x!=1)
     {
      //cout<<x<<" "<<endl;
        if (sz[x])
        return sd[x];
        x=f[x];        
     }
     return 0;
}
int main()
{
//freopen("in.txt","r",stdin); freopen("out.txt","w",stdout);
//freopen("wbtree.in","r",stdin);freopen("wbtree.out","w",stdout);
  memset (head,-1, sizeof (head));
  cin>>n>>m;
  int a,b;
  for ( int i=1;i<n;i++)
  {
    //cin>>a>>b;
    scanf ( "%d%d" ,&a,&b);
    add1(a,b,i);
    add1(b,a,i);      
  }
  f[1]=1;
  dfs(1); //return 0;
  int s;
  while (m--)
  {
        //cin>>s;
        scanf ( "%d" ,&s);
        if (s==1)
        {
          scanf ( "%d" ,&s);
          //cin>>s;
          printf ( "%d\n" ,Q(s));
          //cout<<Q(s)<<endl;    
        }       
        else
        {
         // cin>>a>>b;
         scanf ( "%d%d" ,&a,&b);
          U(a,b); 
        }       
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值