思路:
可以从度的角度来考虑
来考虑相连
如果是两个D>1的结点相连,我们知道这一定是两颗树合并了,那么树++,如果其中一个D=1,那就是一个点和并到了一颗树上,树的个数不变,如果两个D=0的点相连,树的个数++
接下来考虑断开
如果是两个D>1的结点断开,我们知道肯定是1棵树变成了2颗树。如果其中一个D=1,那么就是把一个叶子结点分出去了,树的个数不变。如果两个点的度都为1,那么分成的两个东西都是单个结点,树的数目--
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e8+7;
int n;
int D[maxn];
map<pair<int, int >, int> mp;
int main()
{
    int ans = 0;
    cin >> n;
    for(int i = 1; i <= n; i++){
        int type, u, v;
        cin >> type;
        if(type == 1){
            cin >> u >> v;
            if(u > v) swap(u, v);
            pair<int, int> pi = make_pair(u, v);
            if(mp[pi]){
                continue;
            }
            mp[pi] = 1;
            if(D[u] && D[v]){
                ans--;                //两棵树合并 
            }
            else if(D[u]==0 && D[v] == 0){
                ans++;                //两个结点连成一颗树 
            }
            D[u]++;
            D[v]++;
        }
        else if(type == 2){
            cin >> u >> v;
            if(u > v) swap(u, v);
            pair<int, int> pi = make_pair(u, v);
            if(!mp[pi]){
                continue;
            }
            mp[pi] = 0;
            if(D[u] > 1 && D[v] > 1){
                ans++;
            }
            else if(D[u] == 1 && D[v] == 1){
                ans--;
            }
            D[u]--;
            D[v]--;
        }
        else if(type == 3){
            cout << ans << endl;
        }
    }
 }