问题 B: 黑白树
时间限制: 2 Sec
内存限制: 512 MB
提交: 75
解决: 45
[
提交][
状态][
讨论版]
问题 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;
}