洛谷 P3998 [SHOI2013]发微博

该博客讨论了一种针对社交媒体消息传播的算法,主要涉及用户之间的关注关系和消息传递。通过分析用户发微博和添加/删除好友的记录,可以计算出每个用户接收到的消息数量。文章提出了一种类似于差分的方法,通过逆向处理记录来避免暴力求解导致的超时问题。在处理过程中,每当两个用户成为好友时,会计算之前一个用户发布的所有消息对另一个用户的影响。最终,算法有效地计算了每个用户在所有记录发生后的消息总数。
摘要由CSDN通过智能技术生成

 PS:如果读过题了可以跳过题目描述直接到题解部分

提交链接:洛谷 P3998 [SHOI2013]发微博

题目

题目描述

刚开通的 SH 微博共有 n 个用户(1∼n 标号),在这短短一个月的时间内,用户们活动频繁,共有 m 条按时间顺序的记录:

! x 表示用户 x 发了一条微博;
+ x y 表示用户 x 和用户 y 成为了好友
− x y 表示用户 x 和用户 y 解除了好友关系

当一个用户发微博的时候,所有他的好友(直接关系)都会看到他的消息。

假设最开始所有人之间都不是好友关系,记录也都是合法的(即 + x y 时 x 和 y 一定不是好友,而 − x y 时 x 和 y 一定是好友)。

问这 m 条记录发生之后,每个用户分别看到了多少条消息。

输入格式

第 1 行两个整数 n, m。

接下来 m 行,按时间顺序读入 m 条记录,每条记录的格式如题目所述,用空格隔开。

输出格式

输出一行 n 个用空格隔开的数(行末无空格),第 i 个数表示用户 i 最后看到了几条消息。

样例

输入

2 8
! 1
! 2
+ 1 2
! 1
! 2
- 1 2
! 1
! 2

输出

1 1

说明/提示

对于 100% 的数据,n≤200000, m≤500000

题解

这道题用暴力超时不是显然的嘛……

所以可以用一个所谓类似差分的办法。

只要在加好友的时候减去前面已经发过的消息,再在删好友的时候把发过的消息全部加起来,最后抵消得到的就是这个人对另一个的影响。

事实上,我们会发现他们一开始加了好友但最后不一定会删,所以我们可以考虑把过程倒过来,毕竟只要加了好友的,他们一定会加好友(废话

对,就是这样的,要是看不懂可以感性理解看代码理解一下。

代码实现

//洛谷 P3998 [SHOI2013]发微博
#include<iostream>
#include<cstdio>
#include<bitset>
using namespace std;
int n,m;
int b[500010];
int x[500010][2];
int cnt[200010];
int c[200010];

void in(int &x){
	int nt;
	x=0;
	while(!isdigit(nt=getchar()));
	x=nt^'0';
	while(isdigit(nt=getchar())){
		x=(x<<3)+(x<<1)+(nt^'0');
	}
}

int main(){
	register int i;
	in(n);
	in(m);
	for(i=1;i<=m;++i){
		while((b[i]=getchar())==10);
		if(b[i]==33){
			in(x[i][0]);
		}
		else if(b[i]==43){
			in(x[i][0]);
			in(x[i][1]);
		}
		else{
			in(x[i][0]);
			in(x[i][1]);
		}
	}
	for(i=m;i>=1;--i){
		if(b[i]==33){
			++cnt[x[i][0]];
		}
		else if(b[i]==43){
			c[x[i][0]]+=cnt[x[i][1]];
			c[x[i][1]]+=cnt[x[i][0]];
		}
		else{
			c[x[i][0]]-=cnt[x[i][1]];
			c[x[i][1]]-=cnt[x[i][0]];
		}
	}
	for(i=1;i<n;++i){
		printf("%d ",c[i]);
	}
	printf("%d",c[n]);
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

月半流苏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值