H.Message Bomb
题目链接-H.Message Bomb
题目大意
输入
s
s
s行数据,
如果
t
=
1
t=1
t=1,则表示第x个学生加入了第
y
y
y个组。可以肯定的是,这个学生以前不在这个小组里。
如果
t
=
2
t=2
t=2,则表示第x个学生退出了第
y
y
y个组。可以肯定的是,这名学生目前就在这个组里。
如果
t
=
3
t=3
t=3,则表示第
x
x
x个学生在第
y
y
y个组中发送了一条消息,可以肯定的是,那个学生现在就在小组里
消息将广播给当前在同一组中的所有其他成员,求最后每个人各自收到的消息总数
解题思路
差
分
思
想
差分思想
差分思想
- 可以用
set
统计每个学生加入的组,数组 b b b统计每个组一共中发消息的条数,数组 a a a作为差分数组统计每个人各自收到的消息数 - 当进组时我们就用
s[x].insert(y)
统计,同时a[x]-=b[y]
,即先减去进组之前的消息数,退组时就用s[x].erase(y)
将该组删除,然后只需a[x]+=b[y]
,加上现在该组消息的总数,根据差分思想,即相当于加上从进组到退组这段时间 x x x在 y y y组收到的消息总数 - 当
x
x
x在
y
y
y组发邮件时,因为消息将广播给当前在同一组中的所有其他成员,所以只需
a[x]--,b[y]++
(a[x]--
是为了避免后续统计消息数时加上自己发的消息) - 最后重新按照第二条遍历一遍每人所加入的组,加上相应的邮件数输出即可
- 具体操作见代码
附上代码
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
#define lowbit(x) (x &(-x))
#define endl '\n'
using namespace std;
const int INF=0x3f3f3f3f;
const int dir[4][2]={-1,0,1,0,0,-1,0,1};
const double PI=acos(-1.0);
const double e=exp(1.0);
const double eps=1e-10;
const int M=1e9+7;
const int N=2e5+10;
typedef long long ll;
typedef pair<int,int> PII;
typedef unsigned long long ull;
inline void read(int &x){
char t=getchar();
while(!isdigit(t)) t=getchar();
for(x=t^48,t=getchar();isdigit(t);t=getchar()) x=x*10+(t^48);
}
set<int> s[N];
int a[N],b[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,m,s1;
cin>>n>>m>>s1;
while(s1--){
int t,x,y;
cin>>t>>x>>y;
if(t==1){
a[x]-=b[y];
s[x].insert(y);
}
else if(t==2){
a[x]+=b[y];
s[x].erase(y);
}
else{
b[y]++;
a[x]--;
}
}
set<int>::iterator it;
for(int i=1;i<=m;i++){
for(it=s[i].begin();it!=s[i].end();it++)
a[i]+=b[*it];
cout<<a[i]<<endl;
}
return 0;
}