洛谷P3998[SHOI2013]发微博

洛谷P3998[SHOI2013]发微博

题目链接:https://www.luogu.com.cn/problem/P3998

题目:

题目描述:

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

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

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

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

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

输入格式:

第 1 行两个整数 n, m

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

输出格式:

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

输出输入样例:

输入 #1

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

输出 #1

1 1 

说明/提示

对于100% 的数据,

解题步骤:

50分

这道题先看到x,y有加好友关系,有解除好友关系,可以看做是一个关系网。那么我们可以用前向星加动态开点,即好友建立是建边,好友解除是减边,发信息就是点对应各个点值+1。但是我并没有采取这个思路。因为太麻烦了

那我们来看看如何求x收到y的信息数呢?x收到y信息数=x、y解除好友时y发的信息数-x、y加好友时y发的信息数。

看着是不是有些眼熟?用后面的信息数减去前面的信息数,这不是差分吗。

所以我们的思路是记录每个人发的信息数,利用差分来计算。但是有些人可能到最后都没有解除好友关系,这是我们就要记录,在最后手动解除。徒手拆鸳鸯

 

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int MAXN = 20002;
 5  6 int n,m,x,y;
 7 int send[MAXN],inf[MAXN];
 8 char b;
 9 bool fri[MAXN][MAXN];
10 11 int main()
12 {
13     scanf("%d%d",&n,&m);
14     int i,j;
15     while(m--)
16     {
17         cin >> b;
18         if(b=='!')  scanf("%d",&x),++send[x];
19         if(b=='+')  scanf("%d%d",&x,&y),fri[x][y]=1,fri[y][x]=1,inf[x]-=send[y],inf[y]-=send[x];
20         if(b=='-')  scanf("%d%d",&x,&y),fri[x][y]=0,fri[y][x]=0,inf[x]+=send[y],inf[y]+=send[x];
21     }
22   
23     for(i=1;i<=n;++i)  for(j=1+i;j<=n;++j)  if(fri[i][j])  inf[i]+=send[j],inf[j]+=send[i];
24     for(i=1;i<=n;++i)
25         printf("%d ",inf[i]); 
26     return 0;
27  } 

 

 

 

100分

50分的代码思路中的差分是对的,但是我们要用的bool数组来记录好友关系,后面手动解除好友的时候也是O()的复杂度,明显数据范围太大过不了。叫你拆鸳鸯

那我们换一个思路,如果是差分的话,是两个状态之间的差值,那后面减前面,不就等于前面减后面吗?而我们之所以要用bool数组来记录好友关系是因为不确定最后是否还有人没有解除好友关系。虽然我们不确定每个人解除好友关系的情况,但是我们确定所有人要解除好友关系就一定要加好友。所以如果我们倒着记录,这些问题就迎刃而解啦!

 
 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int MAXN = 500005;
 5  6 int n,m,x,y,send[MAXN],inf[MAXN];
 7 char b,a[MAXN]; 
 8 int xx[MAXN],yy[MAXN];
 9 10 int main()
11 {
12     scanf("%d%d",&n,&m);
13     int i,j=m;
14     while(m--)
15     {
16         cin >> b;
17         a[m+1]=b;
18         if(b=='!')  scanf("%d",&x),xx[m+1]=x;
19         if(b=='+')  scanf("%d%d",&x,&y),xx[m+1]=x,yy[m+1]=y;
20         if(b=='-')  scanf("%d%d",&x,&y),xx[m+1]=x,yy[m+1]=y;
21     }
22     for(i=1;i<=j;++i)
23     {
24         if(a[i]=='!')  ++send[xx[i]];
25         if(a[i]=='+')  inf[xx[i]]+=send[yy[i]],inf[yy[i]]+=send[xx[i]];
26         if(a[i]=='-')  inf[xx[i]]-=send[yy[i]],inf[yy[i]]-=send[xx[i]];
27     }
28     for(i=1;i<=n;++i)
29         printf("%d ",inf[i]); 
30     return 0;
31  }
32  

 

总而言之,这就是一个差分的问题,再加一点小小的巧思。

完结撒花✿✿ヽ(°▽°)ノ✿

 

posted @ 2022-09-29 19:13  于是开始主动营业  阅读(23)  评论(0)    收藏  举报