-
- 题意:给出一张n个结点,m条边的无向图(结点编号为该点权值),可以进行加边、删边、查询操作,查询操作:若任意一点存在其邻边结点比其权值大,该点将会消失(包括其所有邻边)(从权值最小的结点开始依次消失),问最后能剩下的结点个数。
- ps:每次查询结束后,图的状态仍然是查询前的状态。
- 解析:根据题目数据量我们不可能每次查询都将图进行一次遍历,所以我们考虑每加一条边、删一条边对整张图的影响:
- 加边:权值较小点在加边操作前不存在其它比其权值大的点(邻接点),那么小点肯定会被删除,若存在比其大的其他邻接点,说明之前已经在需要删除的结点数量中计算过它;
- 删边:权值较小点在删边操作后不存在其它比其权值小的点,则可从需要删除的结点数量中进行恢复,否则不进行恢复,因为仍然有比它大的结点,它还是会被删。
- 代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 2e5 + 5;
int cnt[N]; //结点u邻边中比结点u权值大的结点个数
int num = 0; //需要被删除的点的数量
int n, m, q;
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
if(u > v) swap(u, v);
if(!cnt[u]) //之前结点u的邻边不存在比其大的结点
num ++;
cnt[u] ++;
}
cin >> q;
while(q --)
{
int op, u, v;
cin >> op;
if(op == 1) //add
{
cin >> u >> v;
if(u > v) swap(u, v);
if(!cnt[u]) //之前结点u的邻边不存在比其大的结点
num ++;
cnt[u] ++;
}
else if(op == 2) //delte
{
cin >> u >> v;
if(u > v) swap(u, v);
cnt[u] --;
if(!cnt[u]) //删除该边后, 结点u的邻边不存在比其大的结点
num --;
}
else if(op == 3) //query
cout << n - num << endl;
}
return 0;
}