时间限制:1秒 内存限制:64M
【问题描述】
n个节点组成的若干棵有根树,树中的每条边都有一个特定的颜色。你的任务是执行m条操作,输出结果。操作一共有3种:
1 x y c:把x的父亲修改成y。如果x=y或x是y的祖先,则忽略这条指令,否则删除x和它原先父亲节点之间的边,而新边的颜色为c。
2 x y c:把x和y的简单路径上的所有边涂成颜色c。如果x和y之间没有路径,则忽略此指令。
3 x y:统计x和y的简单路径上的边数,以及这些边一共有多少种颜色。如果x和y之间没有路径,则输出0。
【输入格式】
第一行为n和m,然后是每个节点的父亲节点编号和该节点与父亲节点之间的颜色(对于根节点,父亲节点编号为0,且“与父亲之间的边的颜色”无意义)。接下来是m条指令。对于每条指令,1<=x,y<=n;对于类型2的指令,1<=c<=30。节点编号为1~n,颜色编号为1~30。
【输出格式】
对于每个类型3指令,输出对应的结果。
【输入样例】
6 6
0 1 1 3 3 0
1 2 1 1 1 1
3 2 3
1 3 2 3
3 2 3
3 5 6
1 6 1 1
3 4 6
【输出样例】
2 2
1 1
0 0
4 3
【样例解释】
【数据规模与约定】
【来源】
《大白书》396页,UVa11994
这道题的正解应该是用动态树来做,但由于我打不来(没学好)所以直接模拟了一下,结果就AC了。
我们直接按题目说的维护一棵树就好了。
建树就不说了(要多用一个数组来维护哪些点在同一棵树),对于操作一我们先判断能不能执行,找一下x和y的公共祖先(由于树会变我直接爬的),如果可以就删去原来的边然后变化,再维护x的子树的深度和归属(就是belong数组,用了记录在哪棵树里)。
对于操作2,直接边爬边改,操作3同样。
其实这样时间复杂度不高(只要不是链),用动态树优化也就优化lca的过程而已。
代码如下:
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=50005;
struct edge
{
int u,v,next;
}e[250005];
int fa[maxn],deep[maxn],n,m,v[maxn],cnt=0,f[maxn]={0},belong[maxn],ttt=0;
bool vis[35];
int read(){
int