黑白图
Problem Description
黑白图是一个由n个点和n-1条边组成的无向连通图。在图中最多只有一个节点的度会超过2,其余点的度要么为1,要么为2。一个节点的度指的是与该节点有边相连的节点的个数。图中的边是有颜色的,要么白色,要么黑色。一开始所有的边都是黑色。
对黑白图我们可以进行以下三种操作:
1)把第i条边变成黑色。第i条边是指在图中编号为i的边。(这里保证第i条边在变色前是白色的)
2)把第i条边变成白色。(这里保证第i条边在变色前是黑色的)
3)找出从点a到点b的最短路,并且在这条路上只有黑边。或者判断出a和b点之间不存在由黑边组成的路。
节点编号从1到n,边的编号从1到n-1。
样例解释:
在样例一中,1号点和2号点由1号边连接。2号点和3号点由2号边连接。在边被着色前,所有的点都是相互连通的。所以从1号点到3号点最短路是2。
如果我们把2号边变成白色,则3号点与其它点将不再连通。
Input
单组测试数据
第一行,有一个整数n(2≤n≤10^5) 表示图中点的个数。
接下来的n-1行表示边的信息。
每行用vi ui(1≤vi,ui≤n,vi≠ui)表示第i条边连接的两个点。
这里保证图一定是黑白图,并且没有自环和重边。
接下来一行,有一个整数m(1≤m≤3*10^5),表示对图进行操作的次数。
接下来有m行,每行用以下形式表示。
首先有一个整数type(1≤type≤3),表示操作的类型。
如果type=1,则表示要把某条变成黑色。这种情况下,后面会跟一个整数id(1≤id≤n-1),表示要变色的边的编号。
如果type=2,则表示要把某条变成白色。这种情况下,后面会跟一个整数id(1≤id≤n-1),表示要变色的边的编号。
如果type=3,则表示要查询两个点之间由黑边组成的最短距离。这种情况下,后面会跟两个整数a,b(1≤a,b≤n,a有可能等于b),表示要查询的两个节点的编号。
具体可参考测试用例。
每行输入中的整数都由一个空格隔开。
边按输入的顺序进行编号。
Output
对于每个type=3的操作,输出a到b的最短距离。
如果不存在从a到b由黑边组成的路径,则输出“-1”(没有引号)。
输出的相对顺序和输入的相对顺序相同。
每个操作输出占一行。
Sample Input
样例一
3
1 2
2 3
7
3 1 2
3 1 3
3 2 3
2 2
3 1 2
3 1 3
3 2 3
样例二
6
1 5
6 4
2 3
3 5
5 6
6
3 3 4
2 5
3 2 6
3 1 2
2 3
3 3 1
Sample Output
输出一
1
2
1
1
-1
-1
输出二
3
-1
3
2
题解:
一棵树,最多只有一个节点的度数超过2。显然将这个点(没有度数超过2的就随便选一个)作为根,这个点下面的每个子树都是链状。DFS将每个点重新编号,保证同一子树内编号连续,同时处理出每个点到根的距离。
利用树状数组维护一段连续编号内的黑点的数量,因为维护的是边的信息,而重新编号的是点,所以将一条边的两点中编号较大的那个点代表这条边,更新都对该点操作即可。如果LCA(u,v)是根,将其作为两条链即可。利用子树编号连续来判断链内黑边的数量即可。
#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-7
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 200100;
const int mod = 998244353;
int cnt, in[maxn], id[maxn], dis[maxn], rot[maxn], p[maxn];
int u[maxn], v[maxn];
vector<int> g[maxn];
int lowbit(int x);
int query(int x);
void Update(int x, int y, int n);
void dfs(int u, int rt, int fa, int d);
int main()
{
int n, m, i, j, k, op, be = -1;
cnt = 2;
scanf("%d", &n);
for(i=2;i<=n;i++)Update(i, 1, n);
for(i=1;i<n;i++){
scanf("%d %d", &u[i], &v[i]);
in[u[i]]++, in[v[i]]++;
if(in[u[i]]>2)be = u[i];
if(in[v[i]]>2)be = v[i];
g[u[i]].push_back(v[i]);
g[v[i]].push_back(u[i]);
}
if(be == -1)be = 1;
id[be] = 1, rot[be]=2;
for(i=0;i<g[be].size();i++)
dfs(g[be][i], cnt, be, 1);
scanf("%d", &m);
while(m--)
{
scanf("%d", &op);
if(op == 1){
scanf("%d", &i);
j = max(id[u[i]], id[v[i]]);
Update(j, -1, n);
}else if(op ==2){
scanf("%d", &i);
j = max(id[u[i]], id[v[i]]);
Update(j, 1, n);
}else{
int l, r;
scanf("%d %d", &l, &r);
if(rot[l] == rot[r]){
if(id[l]>id[r])swap(l,r);
if(id[r]-id[l] == query(id[r])-query(id[l]))
printf("%d\n", dis[r]-dis[l]);
else printf("-1\n");
}else
{
if(id[r]-rot[r]+1+id[l]-rot[l]+1 == query(id[r])-query(rot[r]-1)+query(id[l])-query(rot[l]-1))
printf("%d\n", dis[r]+dis[l]);
else printf("-1\n");
}
}
}
return 0;
}
int lowbit(int x)
{
return x&(-x);
}
void Update(int x, int y, int n)
{
for(int i=x;i<=n;i+=lowbit(i))
p[i] += y;
}
int query(int x)
{
int sum = 0;
for(int i=x;i>0;i-=lowbit(i))
sum += p[i];
return sum;
}
void dfs(int u, int rt, int fa, int d)
{
id[u] = cnt++;
rot[u] = rt;
dis[u] = d;
for(int i=0;i<g[u].size();i++)
if(g[u][i] != fa){
dfs(g[u][i], rt, u, d+1);
}
}