P3998 [SHOI2013]發微博(差分+set維護)
阿新 • • 發佈:2022-03-31
題意
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 最後看到了幾條訊息。
資料範圍
對於 100% 的資料,n≤200000, m≤500000
樣例
input
2 8
! 1
! 2
+ 1 2
! 1
! 2
- 1 2
! 1
! 2
output
1 1
思路
如果一個人發微博了,那麼對於他的所有好友,他的所有好友看到的微博數量就會加1。
考慮y看到的x發的微博數量,其實就是他們成為好友到解除好友之間的x發的微博數量,也就是ans[y]=ans[y]+cnt[x]-(cnt[x])',他們刪除好友時x發的微博數量減去他們剛成為好友時x發的微博數量。
於是我們用cnt[x]記錄x到當前操作的時候已經發了多少微博,並且對於每個點建立一個set,記錄這個點有哪些好友,每次加好友的時候先減去當前該好友發的微博數量,然後在刪好友的時候再加上當前好友已經發的微博數量。
當所有操作結束的時候,需要手動將所有的好友都刪掉,更新微博數量。
code
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; //#pragma GCC optimize(3) #define pb push_back #define is insert #define PII pair<int,int> #define PLL pair<ll,ll> #define show(x) cerr<<#x<<" : "<<x<<endl; //mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count()); //ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);} const ll INF=0x3f3f3f3f3f3f3f3f;//2147483647; const int N=2e5+50,M=1e5+50; const ll mod=998244353; int n,m; int cnt[N],ans[N]; set<int>s[N]; void solve() { cin>>n>>m; for(int i=1;i<=m;i++){ char op;cin>>op; if(op=='!'){ int tmp;cin>>tmp; cnt[tmp]++; } else if(op=='+'){ int x,y;cin>>x>>y; s[x].is(y);s[y].is(x); ans[x]-=cnt[y]; ans[y]-=cnt[x]; } else { int x,y;cin>>x>>y; s[x].erase(y);s[y].erase(x); ans[x]+=cnt[y];ans[y]+=cnt[x]; } } for(int i=1;i<=n;i++){ for(auto j:s[i]){ ans[i]+=cnt[j]; } } for(int i=1;i<=n;i++){ cout<<ans[i]<<" "; } } signed main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int __=1;//cin>>__; while(__--){ solve(); } return 0; }