Description
给定一棵树,边的颜色为黑或白,初始时全部为白色。维护两个操作:
1.查询u到根路径上的第一条黑色边的标号。
2.将u到v 路径上的所有边的颜色设为黑色。
Notice:这棵树的根节点为1
Input
第一行两个数n,m分别表示点数和操作数。
接下来n-? 1行,每行2个数u,v.表示一条u到v的边。
接下来m行,每行为以下格式:
1 v 表示第一个操作
2 v u 表示第二种操作
Output
对于每个询问,输出相应答案。如果不存在,输出0。
Sample Input
5 4
1 2
1 3
2 4
2 5
1 2
2 2 3
1 3
1 4
1 2
1 3
2 4
2 5
1 2
2 2 3
1 3
1 4
Sample Output
0
2
1
2
1
HINT
对于 100% 的数据:n,m<=10^6
题解:
bzoj3910的加强版。
首先把操作离线.过程中可以处理出每条边都是在什么时候被染成黑色。
然后倒着做.那就变成了删边.
用并查集维护即可.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1000010
using namespace std;
int point[N],next[N<<1],f[N],id[N],v[N],deep[N],x,y,n,cnt,m,ans[N],be[N],p[N],fa[N],sum[N],kind;
struct use{int st,en,p;}e[N<<1];
void add(int x,int y,int p){
next[++cnt]=point[x];point[x]=cnt;
e[cnt].en=y;e[cnt].p=p;
}
int find(int x){if (f[x]==x) return f[x];else return f[x]=find(f[x]);}
void dfs(int x){
for (int i=point[x];i;i=next[i])
if (e[i].en!=fa[x]){
id[e[i].en]=e[i].p;fa[e[i].en]=x;
deep[e[i].en]=deep[x]+1;
dfs(e[i].en);
}
}
void up(int x,int y,int k){
x=find(x);y=find(y);
while (x!=y){
if (deep[x]<deep[y]) swap(x,y);
if (be[x]!=m+1) x=f[x];
else be[x]=k,f[x]=f[fa[x]],x=f[x];
}
}
int main(){
scanf("%d%d",&n,&m);int now=n;
for (int i=1;i<=n-1;i++){
scanf("%d%d",&x,&y);
add(x,y,i);add(y,x,i);
}
for (int i=1;i<=n;i++) f[i]=i,be[i]=m+1;
dfs(1);memset(p,-1,sizeof(p));
for (int i=1;i<=m;i++){
scanf("%d",&kind);
if (kind==2){scanf("%d%d",&x,&y);up(x,y,i);}
else {scanf("%d",&x);p[i]=x;}
}
for (int i=1;i<=n;i++) sum[be[i]]++;
for (int i=2;i<=m+1;i++) sum[i]+=sum[i-1];
for (int i=1;i<=n;i++) v[sum[be[i]]--]=i;
for (int i=1;i<=n;i++) f[i]=i;
//for (int i=1;i<=n;i++) cout<<id[i]<<endl;
for (int i=m+1;i>=1;i--){
if (p[i]!=-1) p[i]=id[find(p[i])];
else
for (;be[x=v[now]]==i&&now;now--) f[x]=f[fa[x]];
}
for (int i=1;i<=m;i++) if (p[i]!=-1) printf("%d\n",p[i]);
}