#736 (Div. 2) C. Web of Lies(图论)

题目描述

There are n nobles, numbered from 1 to n. Noble i has a power of i. There are also m “friendships”. A friendship between nobles a and b is always mutual.
A noble is defined to be vulnerable if both of the following conditions are satisfied:
the noble has at least one friend, and
all of that noble’s friends have a higher power.
You will have to process the following three types of queries.
Add a friendship between nobles u and v.
Remove a friendship between nobles u and v.
Calculate the answer to the following process.
The process: all vulnerable nobles are simultaneously killed, and all their friendships end. Then, it is possible that new nobles become vulnerable. The process repeats itself until no nobles are vulnerable. It can be proven that the process will end in finite time. After the process is complete, you need to calculate the number of remaining nobles.
Note that the results of the process are not carried over between queries, that is, every process starts with all nobles being alive!

Input

The first line contains the integers n and m (1≤n≤2⋅105, 0≤m≤2⋅105) — the number of nobles and number of original friendships respectively.
The next m lines each contain the integers u and v (1≤u,v≤n, u≠v), describing a friendship. No friendship is listed twice.
The next line contains the integer q (1≤q≤2⋅105) — the number of queries.
The next q lines contain the queries themselves, each query has one of the following three formats.
1 u v (1≤u,v≤n, u≠v) — add a friendship between u and v. It is guaranteed that u and v are not friends at this moment.
2 u v (1≤u,v≤n, u≠v) — remove a friendship between u and v. It is guaranteed that u and v are friends at this moment.
3 — print the answer to the process described in the statement.

Output

For each type 3 query print one integer to a new line. It is guaranteed that there will be at least one type 3 query.

Examples

input
4 3
2 1
1 3
3 4
4
3
1 2 3
2 3 1
3
output
2
1
input
4 3
2 3
3 4
4 1
1
3
output
1

Note

Consider the first example. In the first type 3 query, we have the diagram below.
In the first round of the process, noble 1 is weaker than all of his friends (2 and 3), and is thus killed. No other noble is vulnerable in round 1. In round 2, noble 3 is weaker than his only friend, noble 4, and is therefore killed. At this point, the process ends, and the answer is 2.
在这里插入图片描述
In the second type 3 query, the only surviving noble is 4.
The second example consists of only one type 3 query. In the first round, two nobles are killed, and in the second round, one noble is killed. The final answer is 1, since only one noble survives.
在这里插入图片描述

题目大意

一个含有n个点m条边的图,我们可以对它进行三种操作:
1.添加一条边
2.删除一条边
3.查询每一个点,如果该点上有边,并且与它相连的都是比他节点编号大的点,那么就删除这些点。循环该过程直到不存在可以删除的点为止。输出最后还能剩下多少点。

题目分析

为了能快速的完成加边和删边操作,我们可以使用 set<int> h[N] 来存图。 这样可以在O(logn)的复杂度下完成这两个操作。

对于操作3,我们可以先算出原图中它的值,然后每次操作完更新答案的变化。因为每次操作之间的答案都是有联系的,因此我们就可以比较快的维护操作3的答案。

剩下的问题就是如何求出操作3的答案已经如何维护它。
我 们 可 以 从 小 到 大 遍 历 每 一 个 点 , 只 要 该 点 上 存 在 边 , 那 就 说 明 该 点 是 应 该 被 删 除 的 。 我们可以从小到大遍历每一个点,只要该点上存在边,那就说明该点是应该被删除的。

进 一 步 对 其 整 理 , 我 们 可 以 发 现 : 对 于 一 个 点 a 来 说 , 只 要 该 点 上 存 在 一 个 比 它 大 的 点 b , 那 么 这 个 点 a 就 应 该 被 删 进一步对其整理,我们可以发现:对于一个点a来说,只要该点上存在一个比它大的点b,那么这个点a就应该被删 aba
除 。 这 样 我 们 就 可 以 在 O ( n l o g n ) 内 算 出 操 作 3 的 答 案 了 除。这样我们就可以在O(nlogn)内算出操作3的答案了 O(nlogn)3

有 了 这 个 结 论 , 维 护 也 就 简 单 了 : 每 添 加 一 条 边 之 前 , 先 看 看 较 小 的 点 之 前 是 否 与 比 它 大 的 点 相 连 , 如 果 是 , 那 有了这个结论,维护也就简单了:每添加一条边之前,先看看较小的点之前是否与比它大的点相连,如果是,那
么 答 案 减 一 ; 么答案减一;

每 删 除 一 条 边 之 后 , 看 看 较 小 的 点 是 否 还 有 与 比 它 大 的 点 相 连 , 如 果 没 有 , 那 么 答 案 加 一 每删除一条边之后,看看较小的点是否还有与比它大的点相连,如果没有,那么答案加一

代码如下
#include <iostream>
#include <cmath>
#include <cstdio>
#include <set>
#include <string>
#include <cstring>
#include <map>
#include <algorithm>
#include <stack>
#include <queue>
#include <bitset>
#define LL long long
#define ULL unsigned long long
#define PII pair<LL,LL>
#define PDD pair<double,double>
#define x first
#define y second
using namespace std;
const int N=2e5+5,mod=1e9+7;
set<int> h[N];
int main()
{
	int n,m,q;
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++)			//建图
	{
		int u,v;
		scanf("%d%d",&u,&v);
		h[u].insert(v);
		h[v].insert(u);
	}
	int ans=0;						//这里的ans是被删除点的个数,不是剩余点的个数
	for(int i=1;i<=n;i++)			//预处理出操作3的答案
		if(h[i].size()&&(*h[i].rbegin())>i) ans++;		//这样我们可以直接找出与i相连的最大值来与i进行比较
	
	scanf("%d",&q);
	while(q--)
	{
		int op,u,v;
		scanf("%d",&op);
		if(op==1)							//加边操作
		{
			scanf("%d%d",&u,&v);
			if(u>v) swap(u,v);				//更新ans
			if(!h[u].size()||(*h[u].rbegin())<u) ans++;
			h[u].insert(v);
			h[v].insert(u);
		}
		else if(op==2)						//删边操作
		{
			scanf("%d%d",&u,&v);
			h[u].erase(v);
			h[v].erase(u);
			if(u>v) swap(u,v);
			if(!h[u].size()||(*h[u].rbegin())<u) ans--;
		}
		else printf("%d\n",n-ans);			//输出答案
	}
 	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值