【51Nod && Codeforce】1809 黑白图 ProblemD.Beard Graph(树链剖分+数组数组)

黑白图是一个由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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值