来源:牛客网:

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小牛牛在暑假的时候返乡务农。为了响应习主席“绿水青山就是金山银山”的号召开始种树。

但他种树的方式比较奇怪。他会先拿出一些有标号的点,然后他会有一些操作,分为3种:添加一条边,切断一条边,询问他有多少个大小不为一的树。当然,年幼的小牛牛记性不是很好,他有时会连出重边,有时也会切断根本不存在的边。当然,对于这样的操作,无视就可以了。

注意看数据范围

输入描述:

第一行一个n

接下来n行,表示n次操作。

每组操作格式如下

1 u v 表示将u点和v点连起来

2 u v 表示将u点和v点之间的边删除

3 表示询问

输出描述:
对每一个3询问输出一个数表示当前大小不为一的树的数量。
示例1
输入
复制

4
1 1926 817
3
2 817 1926
3

输出
复制

1
0

备注:
对于全部数据 1≤n≤10^5^,保证不被忽略的操作1不构成环。1≤u,v≤10^8^

题解:

根据题意可知,就是一个建树拆树的过程,我们可以完全模拟进行
用到set来实现
我们先分析建树,当连接u和v两个点时,会有如下情况:
1.u和v只是两个点,连接后sum++
2.u和v分别是两个树上的点,连接后两树合并为一树,sum - -
3.u和v已连接,那就没有任何影响
sum为树的数量
拆树时(就是建树相反):
1.如果两点未连接,那就没有任何影响
2.如果与u和v连接的点均大于2,也就说明u和v连接前就已经与其他点相连,拆开后一树变两树sum++
3.如果u和v均为彼此相连,拆开后sum--
查询时直接输出结果
map的find和size可以帮助我们实现以上要求
注意:
点的大小并非按顺序,所以即可离散化处理
具体内容看代码

代码:

#include<bits/stdc++.h>
#include<set>
using namespace std;
const int maxn=1e6+9;
int op[maxn];
int c1[maxn],c2[maxn],lsh[maxn];
set<int>tree[maxn];
int main()
{
    int n;
    cin>>n;
    int cnt=0;
    for(int i=1;i<=n;i++)
    {

        cin>>op[i];
        if(op[i]==3)continue;
        else 
        {
            cin>>c1[i]>>c2[i];
            lsh[++cnt]=c1[i];
            lsh[++cnt]=c2[i];
        }


    }
    sort(lsh+1,lsh+1+cnt);
    int ant=unique(lsh+1,lsh+1+cnt)-lsh-1;
    for(int i=1;i<=n;i++)
    {
        c1[i]=lower_bound(lsh+1,lsh+1+ant,c1[i])-lsh;
        c2[i]=lower_bound(lsh+1,lsh+1+ant,c2[i])-lsh;
    }
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        if(op[i]==1)
        {
            int u=c1[i],v=c2[i];
            if(tree[u].find(v)!=tree[u].end())continue;//已存在此边 
            if(tree[u].size()==0&&tree[v].size()==0)sum++;
            if(tree[u].size()&&tree[v].size())sum--;
            tree[u].insert(v);
            tree[v].insert(u);
        }
        else if(op[i]==2)
        {
            int u=c1[i],v=c2[i];
            if(tree[u].find(v)==tree[u].end())continue;//还没有这个边 
            if(tree[u].size()>=2&&tree[v].size()>=2)sum++;
            if(tree[u].size()==1&tree[v].size()==1)sum--;
            tree[u].erase(v);
            tree[v].erase(u);
        }
        else 
        {
            cout<<sum<<endl;
        }
    }
    return 0;
}