黑白图是一个由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号点与其它点将不再连通。
收起
输入
单组测试数据 第一行,有一个整数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),表示要查询的两个节点的编号。 具体可参考测试用例。 每行输入中的整数都由一个空格隔开。 边按输入的顺序进行编号。
输出
对于每个type=3的操作,输出a到b的最短距离。 如果不存在从a到b由黑边组成的路径,则输出“-1”(没有引号)。 输出的相对顺序和输入的相对顺序相同。 每个操作输出占一行。
输入样例
样例一 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
输出样例
输出一 1 2 1 1 -1 -1 输出二 3 -1 3 2
思路:利用DFS序,维护边变化时候的边的数目,最后判断即可
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=100009;
//**********************************树状数组
int c[maxn] ;
void init()
{
memset(c, 0,sizeof(c));
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int d) //在x处加上d
{
for( ; x < maxn ; x+=lowbit(x))
c[x]+=d ;
}
int sum(int x) //求小于等于x的个数
{
int ans = 0 ;
for( ; x>0 ; x-=lowbit(x))
ans +=c[x] ;
return ans ;
}
vector<int> node[maxn];
vector<pair<int,int> > edge;
int degree[maxn],L[maxn],pos[maxn],now,yy,lei[maxn],n,m;
void dfs(int u,int f)
{
L[u]=L[f]+1;
pos[u]=now++;
lei[u]=yy;
for(int i=0; i<node[u].size(); i++)
{
int y=node[u][i];
if(y==f)
continue;
dfs(y,u);
}
}
int main()
{
int a,b,c;
scanf("%d",&n);
now=1;
for(int i=1; i<=n-1; i++)
{
scanf("%d%d",&a,&b);
degree[a]++;
degree[b]++;
node[a].push_back(b);
node[b].push_back(a);
edge.push_back(make_pair(a,b));
}
int root=1;
for(int i=1; i<=n; i++)
{
if(degree[i]>2)
{
root=i;
break;
}
}
L[root]=0;
for(int i=0; i<node[root].size(); i++)
{
yy=node[root][i];
dfs(yy,root);
}
scanf("%d",&m);
for(int i=0; i<m; i++)
{
scanf("%d",&c);
if(c==3)
{
scanf("%d%d",&a,&b);
if(pos[a]>pos[b])
swap(a,b);
if(a==root)
{
if(sum(pos[b])-sum(pos[lei[b]]-1)==0)
printf("%d\n",L[b]);
else
printf("-1\n");
}
else if(lei[a]==lei[b])
{
if(sum(pos[b])-sum(pos[a])==0)
printf("%d\n",L[b]-L[a]);
else
printf("-1\n");
}
else
{
if((sum(pos[b])-sum(pos[lei[b]]-1)==0)&&(sum(pos[a])-sum(pos[lei[a]]-1)==0))
{
printf("%d\n",L[a]+L[b]);
}
else
printf("-1\n");
}
}
else if(c==2)
{
scanf("%d",&a);
a--;
int x=max(pos[edge[a].first],pos[edge[a].second]);
add(x,-1);
}
else
{
scanf("%d",&a);
a--;
int x=max(pos[edge[a].first],pos[edge[a].second]);
add(x,1);
}
}
return 0;
}