题解:
先把所有操作保存下来,然后离线做,用并查集维护点的连通性。先把初始状态时各点所属的树保存下来备份,然后处理所有连边,处理深度和倍增数组。
之后用保存下来的备份复原,按照顺序操作,操作1就变为了并查集中的合并,操作2就需要判断x和y与另一个其他的相对位置来判断答案,深度最深的即为答案。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<climits>
#include<vector>
#define MAXA 1000005
#define MOD 1000000007
using namespace std;
typedef long long LL;
int head[MAXA],cnt;
struct Rx {
int next,to;
}edge[MAXA];
struct Rx2 {
int type,x,y;
}Op[MAXA];
void Add(int u,int v) {
edge[++cnt].next = head[u];
edge[cnt].to = v;
head[u] = cnt;
}
int Ast[MAXA],Depth[MAXA],f[MAXA][21],TreeRoot[MAXA],Ans,Temp;
int FindAst(int x) {
if(Ast[x] == x)
return x;
Ast[x] = FindAst(Ast[x]);
return Ast[x];
}
void DFS(int x,int Root) {
TreeRoot[x] = Root;
for(int i=head[x];i;i=edge[i].next) {
int y = edge[i].to;
if(y == f[x][0]) continue;
f[y][0] = x;
DFS(y,Root);
}
}
void DFS2(int x) {
Depth[x] = Depth[f[x][0]] + 1;
for(int i=head[x];i;i=edge[i].next) {
int y = edge[i].to;
if(y == f[x][0]) continue;
f[y][0] = x;
DFS2(y);
}
}
int LCA(int x,int y) {
if(Depth[x] < Depth[y])
swap(x,y);
for(int i=18;i>=0;i--)
if(Depth[f[x][i]] >= Depth[y])
x = f[x][i];
if(x == y) return x;
for(int i=18;i>=0;i--)
if(f[x][i] != f[y][i]) {
x = f[x][i];
y = f[y][i];
}
return f[x][0];
}
int n,m,x,y,Q,E;
int Root[MAXA];
int main() {
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d",&Root[i]);
scanf("%d",&E);
for(int i=1;i<=n-m;i++) {
scanf("%d %d",&x,&y);
Add(x,y);
Add(y,x);
}
for(int i=1;i<=m;i++)
DFS(Root[i],Root[i]);
memcpy(Ast,TreeRoot,sizeof(Ast));
scanf("%d",&Q);
for(int i=1;i<=Q;i++) {
scanf("%d %d %d",&Op[i].type,&Op[i].x,&Op[i].y);
if(Op[i].type == 1) {
if(FindAst(Op[i].x) == FindAst(Op[i].y)) continue;
Ast[FindAst(Op[i].y)] = FindAst(Op[i].x);
Add(Op[i].x,Op[i].y);
Add(Op[i].y,Op[i].x);
}
}
for(int i=1;i<=n;i++)
f[i][0] = 0;
for(int i=1;i<=m;i++)
if(FindAst(Root[i]) == Root[i])
DFS2(Root[i]);
for(int j=1;j<=18;j++)
for(int i=1;i<=n;i++)
f[i][j] = f[f[i][j-1]][j-1];
memcpy(Ast,TreeRoot,sizeof(Ast));
for(int i=1;i<=Q;i++) {
if(Op[i].type == 1) {
if(FindAst(Op[i].x) == FindAst(Op[i].y)) continue;
Ast[FindAst(Op[i].y)] = FindAst(Op[i].x);
}
else {
if(FindAst(Op[i].x) != FindAst(Op[i].y)) {
printf("orzorz\n");
continue;
}
int xAst = FindAst(Op[i].x);
Ans = LCA(Op[i].x,Op[i].y);
Temp = LCA(Op[i].x,xAst);
if(Depth[Temp] > Depth[Ans]) Ans = Temp;
Temp = LCA(Op[i].y,xAst);
if(Depth[Temp] > Depth[Ans]) Ans = Temp;
printf("%d\n",Ans);
}
}
}
/*
9 3
1 5 8
1 2
1 3
2 4
5 6
5 7
8 9
4
1 6 1
1 6 8
2 9 2
2 4 7
*/